Trouble injecting a value into inner class with Spring? - java

I have a private static inner class that I need to inject a value into and I am having no luck.
My code's pattern is as follows:
#Component
public final class someClassUtil {
#Component
private static class innerClass {
private transient boolean myVar;
#Value("${my.value.to.inject}")
public void setMyVar(final boolean myVar) {
this.myVar = myVar;
}
}
}
I have a feeling that it may have something to do with the access modifiers, but I have tried many variants with no success. Any thoughts?

Since your nested class is private, I fear that Spring's DI mechanism is not able to invoke the setter thus rendering the annotation on it useless.

According to the #Value docs, you need to use #Value("#{my.value.to.inject}"). Note the "#" instead of "$".

Related

Why I cannot use #Value in utility class

These are my utility class and controller class respectively.
#UtilityClass
public class MyUtil {
#Value("${myvalue}")
private String testString;
public String test(){
return testString;
}
}
#GetMapping("/test")
public String gethello(){
return MyUtil.test();
}
It returns the null value.
I fix the issue by following How to read application.properties in utils class
But my question is that why the original approach doesn't work. I just want a reference from the properties file so that I can easily define the parameters. Many thanks.
Spring doesn't support #Value on static fields. Given the lombok #UtilityClass annotation makes all members static, this won't work.

#Service, #Repository class dependency-injection to static field is good for static method usage?

Using static-method makes code more clean.
So I wanna use static-method even used with #Service, #Repository class in it.
You can more easily understand by code. Very short one and It works!!
But I want to know it is okay to use in any situation.
I didn't see like that code before, so I am afraid it is the effective code to use. If you have any idea about that, could you advise me, please?
#Repository
public class TruckRepository {
public Integer selectWheelCount() {
//which is searching truck database to get some data about trucks.
//Such as how many wheels does the truck have, something like that.
}
}
#Component
public class CarFactory {
private static TruckRepository truckRepository;
//#Autowired << can be omitted after spring 4.3 as I know
NewsSourceFactory(TruckRepository truckRepository) {
this.truckRepository = truckRepository;
}
public static Integer getWheelCount(String carType) {
swtich(carType) {
case TRUCK:
return truckRepository.selectWheelCount();
}
}
}
#Component
public class SomeCode {
public void something() {
Integer count = CarFactory.getWheelCount("TRUCK");
}
}
Add Comments
I very empressive the code of "Duration.class", "Stream.class" in java.
They are also using static-method, Of course they have no dynamic injection in there.
Just in case of thinking about the concise of code or clearness, isn't it the merit of static-method, dont you think? is it really harmless?
You are using static method which uses static field which is initialized in constructor. In this code it's not even clear when Spring will create a new instance of CarFactory (maybe it won't at all, if none is referencing it). And if no instance of CarFactory created, your static method is broken too, because static field is not initialized.
I don't see any benefits of using static methods in your case, after all you can always inject instance of CarFactory into SomeCode.
Simple as:
#Autowired
private CarFactory cartFactory;
Or better:
private CarFactory cartFactory;
public SomeCode(#Autowired CarFactory pCartFactory) {
cartFactory = pCartFactory;
}

Spring Boot: #Value returns always null

I would like to use a value from application.properties file in order to pass it in the method in another class. The problem is that the value returns always NULL. What could be the problem? Thanks in advance.
application.properties
filesystem.directory=temp
FileSystem.java
#Value("${filesystem.directory}")
private static String directory;
You can't use #Value on static variables. You'll have to either mark it as non static or have a look here at a way to inject values into static variables:
https://www.mkyong.com/spring/spring-inject-a-value-into-static-variables/
EDIT: Just in case the link breaks in the future. You can do this by making a non static setter for your static variable:
#Component
public class MyComponent {
private static String directory;
#Value("${filesystem.directory}")
public void setDirectory(String value) {
this.directory = value;
}
}
The class needs to be a Spring bean though or else it won't be instantiated and the setter will be not be accessible by Spring.
For the ones still facing the issue after all the preceding suggestions, make sure you are not accessing that variable before the bean has been constructed.
That is:
Instead of doing this:
#Component
public MyBean {
#Value("${properties.my-var}")
private String myVar;
private String anotherVar = foo(myVar); // <-- myVar here is still null!!!
}
do this:
#Component
public MyBean {
#Value("${properties.my-var}")
private String myVar;
private String anotherVar;
#PostConstruct
public void postConstruct(){
anotherVar = foo(myVar); // <-- using myVar after the bean construction
}
}
Hope this will help someone avoid wasting hours.
Few things for you to cross check apart from #Plog's answer.
static variables can't be injected with value. Check #Plog's answer.
Make sure the class is annotated with #Component or #Service
The component scan should scan the enclosing package for registering the beans. Check your XML if xml enabled configuration.
Check if the property file's path is correct or in classpath.
The other answers are probably correct for the OP.
However, I ran into the same symptoms (#Value-annotated fields being null) but with a different underlying issue:
import com.google.api.client.util.Value;
Ensure that you are importing the correct #Value annotation class! Especially with the convenience of IDEs nowadays, this is a VERY easy mistake to make (I am using IntelliJ, and if you auto-import too quickly without reading WHAT you are auto-importing, you might waste a few hours like I did).
Of course, the correct class to import is:
import org.springframework.beans.factory.annotation.Value;
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
You can make use of this. reference to assess the value of (private String myVar)
this.myVar
Add the #Autowired annotation to the variable declaration of your class.
#Autowired
private FileSystem myFileSystem;

Spring: Is it possible to have a duplicate constructor with different qualifier while autowiring?

I am trying to autowire a member in a class using the constructor.
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(ClassA objectA) {
myMember = objectA;
}
}
If I have multiple sources that create beans of ClassA, is it possible to have a duplicate constructor definition that instantiates based on the bean that was autowired into this class?
I want to do something like this:
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA) {
myMember = objectA;
}
#Autowire
public MyClass(#Qualifier ("qualifierB") ClassA objectB) {
myMember = objectB;
}
}
I tried using #Qualifier this way, but it didn't work.
Is it possible to do what I'm trying to do, with Spring? How can I disambiguate based on the name (qualifierA) or (qualifierB), if the bean definition is like:
#Bean (name = "qualifierA")
public ClassA getQualifierA() {
...
}
#Bean (name = "qualifierB")
public ClassA getQualifierB() {
...
}
You can't have two constructors with the exact same signature in a single class in Java. Nor any other programming language I've ever encountered. You might use method-injection instead, with two methods (named differently, of course), mark them as #Autowired(required = false) and use the proper #Qualifier(...) to specify the instance you want to inject. You might want to handle the case when both instances are present in the spring context, so no unexpected things happen.
The short answer is: no, that is not possible. In Java you cannot have two constructors with exactly the same signature. And also, you can assign only one value to your "myMember".
However, what are you trying to accomplish here? It seems that in some occasions MyClass needs to use "objectA" and in other occasions, you need "objectB".
For these scenarios, you should not use autowiring (you can't), but simply use explicit wiring:
#Bean
MyClass myObject() {
return new MyClass(qualifierA());
}

Java constructor with Guice injected fields along with non-injected fields

I have a class which has a constructor where all the arguments are injected by GUICE.
Public class Order {
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
#Inject
public order(ClassOne classOneObj, ClassTwo classTwoObj){
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
}
Now, I want to add one more field(say, int status)variable which can't be injected.
Is it a good practice to create an object first with all the injected parameters and then set the new field which can't be injected with a setter method?
I came up with another approach where I created a factory class as given below:
public class OrderFactory {
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
#Inject
public order(ClassOne classOneObj, ClassTwo classTwoObj){
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
//getter methods for all the above variables
public ClassOne getclassOneObj(){
return classOneObj;
}
....
public Order createOrder(int status) {
return new Order(status, classOneObj, classTwoObj);
}
}
Then the new Order class will look like
public class Order {
int status
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
public order(int status, ClassOne classOneObj, ClassTwo classTwoObj){
this.status = status
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
//getter methods for all these member variables
}
Now to create the order object I will first create an OrderFactory object and then using the "createOrder" method I will create the Order object.
I am ending up with writing boilerplate code. Not sure if this is a good practice. Can anybody suggest on this if this approach is correct or there is any better approach for this problem?
I read in Google Guice and found there is a feature #Assisted for assisted injection for such cases. But I found that complex and couldn't convince myself whether I should go with that in my case.
Thanks in advance for any suggestion or guidance.
Your factory approach is excellent. Please don't use the setters: if the field can be made immutable, it should be immutable, whether or not it makes it "convenient" to instantiate.
Another approach you can take is Assisted Injection, which solves this exact problem. With that, you only define the factory interface, and its implementation is magically given to you by Guice:
class Order {
interface Factory {
Order create(Status status);
}
#AssistedInject Order(
ClassOne one,
ClassTwo two,
#Assisted Status status) {
}
}
Module code:
bind(Order.Factory.class).toProvider(
FactoryProvider.newFactory(Order.Factory.class, Order.class));
Then the clients inject Factory and use it just like they do in your example.
You're typically going to inject things that take some amount of effort to construct. If you're just injecting an int field, you'd be better off just calling a setter method on the object (that has some of it's more complex dependencies injected). Also, if a fields changes frequently, as implied by a field called "status", then it's also not a good candidate for injection.

Categories

Resources