Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign a value from application.properties to a static variable?

I am using Spring MVC. I have a UserService class annotated with @Service that has a lot of static variables. I would like to instantiate them with values from the application.properties file.

For example in application.properties I have: SVN_URL = http://some.url/repositories

Then in the class there is: @Value("${SVN_URL}") private static String SVN_URL

I get the Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError

I have also tried @Autowired private static Environment env;

And then: private static String SVN_URL=env.getProperty("SVN_URL");

It gives the same error.

like image 909
dannemp Avatar asked Jul 19 '17 13:07

dannemp


People also ask

How do you assign a value to a static variable?

Values can be assigned during the declaration or within the constructor. Additionally, values can be assigned in special static initializer blocks. Static variables can be accessed by calling with the class name ClassName. VariableName.

How do you inject a value to a static field?

Solution First, PropertyController, which is a RestController, is being initialized by Spring. Afterward, Spring searches for the Value annotated fields and methods. Spring uses dependency injection to populate the specific value when it finds the @Value annotation.

How do you set value in application properties?

You can use @Value("${property-name}") from the application. properties if your class is annotated with @Configuration or @Component . You can make use of static method to get the value of the key passed as the parameter.

Can we reassign value to static variable in C?

When static keyword is used, variable or data members or functions can not be modified again. It is allocated for the lifetime of program. Static functions can be called directly by using class name.


3 Answers

Think about your problem for a second. You don't have to keep any properties from application.properties in static fields. The "workaround" suggested by Patrick is very dirty:

  • you have no idea when this static field is modified
  • you don't know which thread modifies it's value
  • any thread at any time can change value of this static field and you are screwed
  • initializing private static field that way has no sense to me

Keep in mind that when you have bean controlled by @Service annotation you delegate its creation to Spring container. Spring controls this bean lifecycle by creating only one bean that is shared across the whole application (of course you can change this behavior, but I refer to a default one here). In this case any static field has no sense - Spring makes sure that there is only one instance of UserService. And you get the error you have described, because static fields initialization happens many processor-cycles before Spring containers starts up. Here you can find more about when static fields are initialized.

Suggestion

It would be much better to do something like this:

@Service
public class UserService {
    private final String svnUrl;

    @Autowired
    public UserService(@Value("${SVN_URL}") String svnUrl) {
        this.svnUrl = svnUrl;
    }
}

This approach is better for a few reasons:

  • constructor injection describes directly what values are needed to initialize the object
  • final field means that this value wont be changed after it gets initialized in a constructor call (you are thread safe)

Using @ConfigurationProperties

There is also another way to load multiple properties to a single class. It requires using prefix for all values you want to load to your configuration class. Consider following example:

@ConfigurationProperties(prefix = "test")
public class TestProperties {

    private String svnUrl;

    private int somePort;

    // ... getters and setters
}

Spring will handle TestProperties class initialization (it will create a testProperties bean) and you can inject this object to any other bean initialized by Spring container. And here is what exemplary application.properties file look like:

test.svnUrl=https://svn.localhost.com/repo/
test.somePort=8080

Baeldung created a great post on this subject on his blog, I recommend reading it for more information.

Alternative solution

If you need somehow to use values in static context it's better to define some public class with public static final fields inside - those values will be instantiated when classloader loads this class and they wont be modified during application lifetime. The only problem is that you won't be able to load these values from Spring's application.properties file, you will have to maintain them directly in the code (or you could implement some class that loads values for these constants from properties file, but this sounds so verbose to the problem you are trying to solve).

like image 158
Szymon Stepniak Avatar answered Oct 17 '22 05:10

Szymon Stepniak


Spring does not allow to inject value into static variables.

A workaround is to create a non static setter to assign your value into the static variable:

@Service
public class UserService {

    private static String SVN_URL;

    @Value("${SVN_URL}")
    public void setSvnUrl(String svnUrl) {
        SVN_URL = svnUrl;
    }

}
like image 28
Patrick Avatar answered Oct 17 '22 06:10

Patrick


Accessing application.properties in static member functions is not allowed but here is a work around,

application.properties

server.ip = 127.0.0.1

PropertiesExtractor.java

public class PropertiesExtractor {
     private static Properties properties;
     static {
        properties = new Properties();
        URL url = new PropertiesExtractor().getClass().getClassLoader().getResource("application.properties");
        try{
            properties.load(new FileInputStream(url.getPath()));
           } catch (FileNotFoundException e) {
                e.printStackTrace();
           }
        }

        public static String getProperty(String key){
            return properties.getProperty(key);
        }
}

Main.class

public class Main {
    private static PropertiesExtractor propertiesExtractor;
    static{
         try {
             propertiesExtractor = new PropertiesExtractor();
         } catch (UnknownHostException e) {
               e.printStackTrace();
           }
    }

    public static getServerIP(){
        System.out.println(propertiesExtractor.getProperty("server.ip")
    }
}
like image 8
Jalaz Kumar Avatar answered Oct 17 '22 07:10

Jalaz Kumar