Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Value annotation always evaluating as null?

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?

like image 290
Polaris878 Avatar asked Nov 09 '10 04:11

Polaris878


People also ask

What does the @value annotation do?

@Value is a Java annotation that is used at the field or method/constructor parameter level and it indicates a default value for the affected argument. It is commonly used for injecting values into configuration variables - which we will show and explain in the next part of the article.

What does @value annotation do in spring boot?

Spring @Value annotation is used to assign default values to variables and method arguments. We can read spring environment variables as well as system variables using @Value annotation. Spring @Value annotation also supports SpEL.

Can I use @value in @service?

@Value annotation can be used within classes annotated with @Configuration , @Component and other stereotype annotations like @Controller , @Service etc. The actual processing of @Value annotation is performed by BeanPostProcessor and so @Value cannot be used within BeanPostProcessor class types.

Can I use @value in pojo?

For the record, the specification of what a POJO is, means that the class cannot contain pre-specified annotations. So even in another world where @Value could work on a non-spring bean, it would still, by definition, break the POJO aspect of the class.


3 Answers

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.

like image 194
skaffman Avatar answered Sep 30 '22 00:09

skaffman


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.

like image 25
Rob Avatar answered Sep 29 '22 23:09

Rob


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).

The correct import is:

org.springframework.beans.factory.annotation.Value

like image 20
scottysseus Avatar answered Sep 30 '22 00:09

scottysseus