Spring @Value annotation always evaluating as null?
Asked Answered
T

8

65

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?

Thibaut answered 9/11, 2010 at 4:22 Comment(5)
Is Config class defined as a spring bean?Quorum
no? How would I do that with annotations?Thibaut
I tried using "@Component" and "@Controller" on the class and neither workedThibaut
How its working in Controller then? What's different in your Controller?Felloe
That is what is so perplexing to me... the Config class is in the same package and everything... the only difference is that with my Controller that works I actually have a request mapping.Thibaut
P
75

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.

Po answered 9/11, 2010 at 8:46 Comment(6)
Hey skaffman, thanks for the advise... The issue is that I'm instantiating Config from a JSP. I'm not sure if I can find a way around that? Maybe by using some sort of factory?Thibaut
@Polaris878: My suggestion should still work for JSP-instantiated objects (any any object instantiated via reflection)Po
+1. I seize to know about Spring in that detail. Didn't touch it for years. Stupid workplace.Felloe
+1 Oh my... this saves me! Was trying to read property files and wasn't sure why @Value was giving nullCourbevoie
I tried all the guides, checked config like 50 times, used all the possible annotations.. Nearly went crazy, and then I decided to test if a controller sees the property.. Yes! And the service - too! In my case, that was actually the object used in the service initialized with new :DOzzie
Thanks, that was it. I was trying to instantiate a new object rather than autowire the class and let Spring do the work.Iva
F
45

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.

Fluoro answered 23/8, 2013 at 13:21 Comment(5)
what is myProperties here. could you please explain.Unesco
It was #2 in my case. Switching from declaration as new to @Autowired solved my problem.Peroxidize
I can confirm the properties are being set in my @Serviceclass, however when I try to reference those fields by pulling it into another class via @Autowired private MyService myservice, those fields are now null. Why is this happening?Grimbal
i had to add "@ConfigurationProperties" to a configclass (no instantiations of that class with "new") then you can "@Autowire" that class and annotated "@Value" fields "work"Dissemblance
You have saved my life. Thanks.Foliolate
I
6

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

Indispose answered 11/12, 2018 at 17:17 Comment(3)
Great finding! In my case, I was overshading the regular spring boot dependencies with "org.springframework.boot" pluginOstwald
what is the correct annotation? this should be provided in an answerJerryjerrybuild
I added the correct import to the answerIndispose
F
4

As its working with @Controller, it seems you are instantiating Config yourself. Let the Spring instantiate it.

Felloe answered 9/11, 2010 at 4:57 Comment(2)
Ahhh yeah that is the problem... I'm calling the constructor myself. How then, could I access these properties? If I can't access these properties, that basically means I need to find some other way to load configuration, as the Spring properties loader just won't cut it if those properties are only available in certain scenarios.Thibaut
@Polaris878: Let the Spring instantiate it. Do we have any issues with that? Or do it yourself using ResourceBundle.Felloe
T
3

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 myProperty;

    private static String myOtherProperty;

    @Value("${my.value}")    
    public void setMyProperty(String myValue) {
    this.myProperty = myValue;}

    @Value("${other.value}")
    public void setMyOtherProperty(String otherValue) {
    this.myOtherProperty = otherValue;}

    //rest of your code...
}
Tseng answered 21/5, 2018 at 5:59 Comment(2)
I think that maybe since your fields are static, you were running into a similar issue that I did.Tarsier
in other words: if your fields were not static, you might be able to do field annotation with @Value, instead of your method-level annotation (and maybe not even need setter methods altogether).Tarsier
H
2

Add <context:spring-configured /> to you application context file.

Then add the @Configurable annotation to Config class.

Hughs answered 28/4, 2012 at 2:30 Comment(0)
T
1

Try to make sure the fields on your Bean, that want to be instantiated by @Value, are NOT static (instead are instance). I think something to do with the Spring Context loaded, needed for the Annotations to work, might not happen by the time of static initialization (and instead needs to have an instance loaded into Spring Context).

This:

@Value("${my.property.name}")
String myProperty

NOT this:

@Value("${my.property.name}")
static String myProperty
Tarsier answered 22/5, 2023 at 19:6 Comment(0)
C
0

In my case in my unit test, executeScenarioRequest always is null

@RunWith(SpringRunner.class)
@ExtendWith(MockitoExtension.class)
class ScenarioServiceTestOld {

    @Value("classpath:scenario/SampleScenario.json")
    Resource executeScenarioRequest;

Change @ExtendWith(MockitoExtension.class) to @ExtendWith(SpringExtension.class)

Clinometer answered 14/4, 2022 at 17:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.