Spring: How to inject a value to static field?
Asked Answered
P

5

113

With this class

@Component
public class Sample {

    @Value("${my.name}")
    public static String name;


}

If I try Sample.name, it is always 'null'. So I tried this.

public class Sample {

    public static String name;

    @PostConstruct
    public void init(){
        name = privateName;
    }

    @Value("${my.name}")
    private String privateName;

    public String getPrivateName() {
        return privateName;
    }

    public void setPrivateName(String privateName) {
        this.privateName = privateName;
    }  

}

This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?

Phillip answered 31/8, 2011 at 7:12 Comment(1)
This won't solve; if the static variable is used before object creation. e.g) if the static variable is used under static block to construct the resource, then the resource will be constructed with null.Yarak
F
147

First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.

Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:

@Value("${my.name}")
public void setPrivateName(String privateName) {
    Sample.name = privateName;
}  

(works with @Autowired/@Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.

Fou answered 31/8, 2011 at 7:18 Comment(8)
For "public static non-final fields are evil", could you please give me some references?Shag
Non-final means you can modify the field value, which, for a static field, implies handling thread concurrency - a.k.a. pain in the stack.Marvismarwin
How to use @Value with Static block? Kindly guide us... Regards, NehaLandlubber
Just FYI: The above code will cause a Sonar / Checkstyle violation (if you're bothered about that kind of thing) as you have an instance method writing to a static field.Bowstring
It's possible to mimick the final aspect by using a static setter which will only set the value if it's currently null. So you allow only one modification of the field. (which of course has been made private and use a getter to access it). Spring can call static method in his configuration phase (XML or Annotation).Witness
@Tomasz Nurkiewicz, do you have any Spring documentation of why they are evil?Dysphasia
@Dysphasia that’s not just a spring thing. static fields that can be modified are just messy disasters waiting to happen. any field being modified should be tied to an instanceHelminth
I 100% agree. I was just looking for a reference document.Dysphasia
S
3

Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field

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;
    }
}
Schnabel answered 7/5, 2020 at 20:12 Comment(0)
F
0

This is my sample code for load static variable

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class OnelinkConfig {
    public static int MODULE_CODE;
    public static int DEFAULT_PAGE;
    public static int DEFAULT_SIZE;

    @Autowired
    public void loadOnelinkConfig(@Value("${onelink.config.exception.module.code}") int code,
            @Value("${onelink.config.default.page}") int page, @Value("${onelink.config.default.size}") int size) {
        MODULE_CODE = code;
        DEFAULT_PAGE = page;
        DEFAULT_SIZE = size;
    }
}
Freberg answered 1/11, 2020 at 18:25 Comment(0)
F
0

For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.

Fireresistant answered 19/10, 2021 at 11:32 Comment(0)
R
0

Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:

public class InjectableClass{
     @Value("${my.value}")
     private String myString;
    
     public String nonStaticMethod(){
           return myString;
     }
}

public class LogicClass{
    private InjectableClass injectableClass;
    @Autowire
    public LogicClass(InjectableClass injectableClass){
       this.injectableClass = injectableClass;
    }

    public void logicClassMethod(){
        System.out.println("Hey! Here is the value I set on myString: " + 
                         injectableClass.nonStaticMethod() + ". That was 
                          basically like using a static method!");
    }
 }
Ricky answered 10/2, 2022 at 0:29 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.