Spring Boot: #Value returns always null - java

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;

Related

Invoke method using spring SPEL with property

Is it possible to use a property value to invoke a method while assigning a value?
For instance, I know I can do this:
#Value("${name}")
private String name; // will have the value of the `name` property
I wonder if it's possible to do something like this:
#Value("#{myMethod(${name})}")
private String myModifiedVariable; // will have the result of invoking myMethod
After my research and a bit of testing, I found there is a way shown in this article Spring EL method invocation, But mybean should be a string bean
#Value("#{mybean.myMethod('${name}')}")
private String myModifiedVariable;
And if you want to call a method in the existing class then use the spring bean name of the same class
#Configuration // or any sterotype annoations
public class TestConfig {
#Value("#{testConfig.myMethod('${name}')}")
private String myModifiedVariable;
public String getValue(String val){
return val+"testValue";
}
}
When using interface projection (in Spring Data Repository) it is possible to call a static method like this:
public interface MyProjection {
// Here we are creating a 2 element list with 'Spring Data' and value taken from "MY_COLUMN_NAME" column
#Value("#{T(java.util.Arrays).asList('Spring Data', target.MY_COLUMN_NAME)}")
List<String> getSampleList();
}
You can also obtain a value of an enum (constant) with above notation. Sample for Spring Security check:
#PreAuthorize("hasRole(T(com.acme.UserRoles).ADMINISTRATOR.name())")
Similar notation should work in other places. Simply remember to use full path to class

Correct way to get environment variables and go through SonarLint

I have a problem reading my environment variables and satisfying SonarLint(detect and fix quality issues) at the same time ..
That way it does not work my variable is null
private String accessKey;
#Value("${bws.access.key}")
public void setAccessKey(String ak){
accessKey=ak;
}
Changing the method to static (as the sonarLint recommends) does not work the variable continuous null
private static String accessKey;
#Value("${bws.access.key}")
public static void setAccessKey(String ak){
accessKey=ak;
}
The only way I found to work is to mark the instance variable as static but not to mark the method as static
private static String accessKey;
#Value("${bws.access.key}")
public void setAccessKey(String ak){
accessKey=ak;
}
But there sonarLint points out the issue
Instance methods should not write to "static" fields
Is not this way I'm getting my enviroment variables across the boundaries not the right one?
You can use the following code:
A Configuration Class (annotated with #Component in order to be picked up by Spring) which will hold the values coming from the properties file, where you bind the value of bws.access.key to a property directly. And if you need accessor methods for accessKey you can just create them (setAccessKey and getAccessKey)
#Component
public class ConfigClass {
// #Value("${bws.access.key:<no-value>}") // <- you can use it this way if you want a default value if the property is not found
#Value("${bws.access.key}") // <- Notice how the property is being bind here and not upon the method `setAccessKey`
private String accessKey;
// optional, in case you need to change the value of `accessKey` later
public void setAccessKey(String ak){
this.accessKey = ak;
}
public String getAccessKey() {
return this.accessKey;
}
}
For more details checkout this GitHub sample project.
I tested this with
IntelliJ IDEA 2018.1.5 (Ultimate Edition),Build #IU-181.5281.24
SonarLint
(Edit) How to use it in a Controller:
An option (there are others) could be to declare a constructor for the controller (let's call it SampleController) and request a parameter of type ConfigClass inside it. Now we set a controller attribute (config) of the same type to the value received as parameter, like this:
#RestController
public class SampleController {
private final ConfigClass config;
public SampleController(ConfigClass configClass) { // <- request the object of type ConfigClass
this.config = configClass; // <- set the value for later usage
}
#RequestMapping(value = "test")
public String test() {
return config.getAccessKey(); // <- use the object of type ConfigClass
}
}
Now, Spring Boot will try to find a component (of any type) in the app of type ConfigClass and since we have one defined it will automatically inject it in our controller. This way you can set the parameter controller property config to the value received in configClass for later usage.
In order to test it, you can request the url test. You will see that the output will be anotherValue. So we can conclude that the Dependency Injection Mechanism successfully found an instance of ConfigClass and the method ConfigClass#getAccessKey works properly.

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.

How can I interpolate a class constant in a Spring `#Value` annotation?

I want to let Spring assign a property value.
public class Foobar {
#Value("${example.property.foo:bar}")
private String foo;
}
Let's say I want to refer to example.property.foo in several different places, so I'd rather assign the flag as a constant on Foobar:
public class Foobar {
public static final String FOO_PROPERTY_FLAG = "example.property.foo";
}
The setting of example.property.foo=whatever happens elsewhere (as a system property, or in a #TestPropertySource).
How can I refer to FOO_PROPERTY_FLAG in the annotation? This works:
#Value("${" + FOO_PROPERTY_FLAG + ":bar}")
But it's kind of ugly. Can I use the "#{}" expression syntax here somehow?
#Value("${#{FOO_PROPERTY_FLAG}:bar}") // doesn't work; value is never injected
You can do something like:
public static final String KEY = "propertyName";
#Value("#{T(a.b.c.package.MyConstants).KEY}")
The important part is to specify package and class. Otherwise spring will try to lookup constant in BeanExpressionContext which is actually executing your SpEL
private #Value("${propertyName}") String propertyField;
No getters or setters!
With the properties being loaded via the config:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:propertyFile.properties" name="propertiesBean"/>
There's also the totally non-Xml version:
#PropertySource("classpath:propertyFile.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Make sure and add in the namespace URI xmlns:p="springframework.org/schema/p"; to use the p: prefixed attributes

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

Categories

Resources