So, I have a simple properties file with the following entries:
my.value=123
another.value=hello world
This properties file is being loaded using a PropertyPlaceHolderConfigurer
, which references the properties file above.
I have the following class, for which I'm trying to load these properties in to like so:
public class Config
{
@Value("${my.value}")
private String mValue;
@Value("${another.value}")
private String mAnotherValue;
// More below...
}
The problem is that, mValue
and mAnotherValue
are ALWAYS null... yet in my Controllers, the value is being loaded just fine. What gives?
If instances of Config
are being instantiated manually via new
, then Spring isn't getting involved, and so the annotations will be ignored.
If you can't change your code to make Spring instantiate the bean (maybe using a prototype
-scoped bean), then the other option is to use Spring's load-time classloader weaving functionality (see docs). This is some low-level AOP which allows you to instantiate objects as you normally would, but Spring will pass them through the application context to get them wired up, configured, initialized, etc.
It doesn't work on all platforms, though, so read the above documentation link to see if it'll work for you.
I had similar issues but was a newbie to Spring.
I was trying to load properties into an @Service, and tried to use @Value to retrieve the property value with...
@Autowired
public @Value("#{myProperties['myValue']}") String myValue;
I spend a whole day trying various combinations of annotations, but it always returned null.
In the end the answer as always is obvious after the fact.
1) make sure Spring is scanning your class for annotations by including the package hierachy
In your servlet.xml (it will scan everything below the base value you insert.
2) Make sure you are NOT 'new'ing the class that you just told Spring to look at. Instead, you use @Autowire in the @Controller class.
Everything in Spring is a Singleton, and what was happening was Spring loaded the values into its Singleton, then I had 'new'ed another instance of the class which did not contain the newly loaded values so it was always null.
Instead in the @Controller use...
@Autowired
private MyService service;
Debugging...
One thing I did to find this was to extend my Service as follows...
@Service
public class MyService implements InitializingBean
Then put in debug statements in...
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
LOGGER.debug("property myValue:" + myValue);
}
Here I could see the value being set on initialization, and later when I printed it in a method it was null, so this was a good clue for me that it was not the same instance.
Another clue to this error was that Tomcat complained of Timeouts trying to read from the Socket with Unable to parse HTTPheader... This was because Spring had created an instance of the service and so had I, so my one was doing the real work, and Spring was timing out on its instance.
As its working with @Controller
, it seems you are instantiating Config
yourself. Let the Spring instantiate it.
Add <context:spring-configured />
to you application context file.
Then add the @Configurable
annotation to Config
class.
You can also make your properties private
, make sure your class is a Spring bean using @Service
or @Component
annotations so it always gets instantiated and finally add setter methods annotated with @Value
. This ensures your properties will be assigned the values specified in your application.properties or yml config files.
@Service
public class Config {
private static String mValue;
private static String mAnotherValue;
@Value("${my.value}")
public void setmValue(String mValue) {
this.mValue = mValue;}
@Value("${another.value}")
public void setmAnotherValue(String mAnotherValue) {
this.mAnotherValue = mAnotherValue;}
//rest of your code...
}
See my answer here.
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).