Why I cannot use #Value in utility class - java

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.

Related

Spring #Component not reading .properties field properly

I've got several #Configuration classes which do specify custom #ConfigurationProperties("sample") and are used within to instantiate several beans that are going to be used my business logic classes later on.
However, I've been trying to do this approach with an inner #Component class so I don't need to fit that within an existing specific or generic config and see what happens.
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
(Constructor, getters and setters for attribute and other methods...)
}
And within my application.properties file I do specify that attribute value as myclass.attribute=value.
Doing it this way results in a null value everytime. Do #Component accept reading .properties file or should it still be in a #Configuration class?
I should have put it as a comment. But didn't want someone to miss this trivial thing.
Okay the issue is - You are missing the '$' (DOLLAR SYMBOL). Wondering why nobody noticed it?
In your properties file if you have this :
myclass.attribute=value
Then to access it in any class, do this:
#Value("${myclass.attribute}")
Noticed the $ symbol above??
Everything is working as expected, even using #ConfigurationProperties in class annotated with #Component. Please try :
application.properties :
myclass.attribute=value
MyClass class :
#Data
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
}
Test class :
#RunWith(SpringRunner.class)
#SpringBootTest
public class FooTests {
#Autowired
private MyClass myClass;
#Test
public void test() {
System.out.println(myClass.getAttribute());
}
}
You do need the #EnableConfigurationProperties annotation on on of you configuration classes, eg the application class.
#SpringBootApplication
#EnableConfigurationProperties
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}
I've never used the #ConfigurationProperties annotation but if you want to set your attribute from a value in your application.properties I'll recommend using the #Value annotation :
application.properties :
myclass.attribute=foo
#Component
public class MyClass {
#Value("myclass.attribute")
private String attribute;
// ...
}
This way every instance of MyClass will have attribute with the default value foo

Property values in yml file not loading into a class in springboot project

Please find the code below for application.yml
decrypt: /Users/Blahblah/Bleh
The above property we're trying to read into a Class please find the code for PropertyLoader.java
#Configuration
#Component
public class PropertyLoader implements InitializingBean{
#Value("${decrypt}")
private String decryptPath;
<--->
}
the value decryptPath is always null. Can anyone tell me what is wrong with the code?
Firstly application.yml should be under the src/main/resources/application.yml.
If you want to use this variables in constructor, you don't. Because spring inject #Value annotated variables after the construction.But if you want to do in constructer you can do like :
public class PropertyLoader implements InitializingBean{
private String decryptPath;
public PropertyLoader(#Value("${decrypt}") decrypPath) {
this.decryptPath = decryptPath;
}
}
It turns out since this class is implementing InitializingBean, the properties object won't be initialized until this class has completed execution. The #Value will always return null.

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;

Trouble injecting a value into inner class with Spring?

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 "$".

Get the class on which the annotation is applied

I am building a custom annotation inside which there is a field of Class type. How do I set a value in it while using the annotation?
Code is given below :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SpringCache {
String putIt();
String getIt();
Class c();
}
This is my custom annotation. Now while I use it how do I give class to variable "c"?
#SpringCache(putIt="I'm put", getIt="I'm get", c=<??>)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
As in this case I want c=TestSpringCache.class.
You just write the class you want:
#SpringCache(putIt="I'm put", getIt="I'm get", c=TestSpringCache.class)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
You might have to add an import statement, if it is not in the same package.
You have to optain all class instances from ApplicationContext (you can inject it), ctx.getBean(). There you can check if an annotation is present.
Actually I didn't find the solution for this. As said by many it does not seem to be possible. Though I have found a work around this.
I removed the class type and kept only String and Boolean type variable there, and to get the annotated classes I took the path from the user to the package containing classes with the defined annotation. And then for each class in the package I checked for the annotation. If annotation was present I did what I wanted to, else did nothing.
Thanks to everyone for giving your time to this.

Categories

Resources