37

I have a Spring Boot application and in one of the classes, I try to reference a property from the application.properties file using @Value. But, the property does not get resolved. I have looked at similar posts and tried following the suggestions, but that didn't help. The class is:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class PrintProperty {

  @Value("${file.directory}")
  private String fileDirectory;

  public void print() {
    System.out.println(fileDirectory);
  }
}

I have the property file.directory in application.properties. I have other fields as well.

kukkuz
  • 41,512
  • 6
  • 59
  • 95
user6641655
  • 523
  • 2
  • 8
  • 13

8 Answers8

27

I had the same problem like you. Here's my error code.

@Component
public class GetExprsAndEnvId {
    @Value("hello")
    private String Mysecret;


    public GetExprsAndEnvId() {
        System.out.println("construct");
    }


    public void print(){
        System.out.println(this.Mysecret);
    }


    public String getMysecret() {
        return Mysecret;
    }

    public void setMysecret(String mysecret) {
        Mysecret = mysecret;
    }
}

This is no problem like this, but we need to use it like this:

@Autowired
private GetExprsAndEnvId getExprsAndEnvId;

not like this:

getExprsAndEnvId = new GetExprsAndEnvId();

Here, the field annotated with @Value is null because Spring doesn't know about the copy of GetExprsAndEnvId that is created with new and didn't know to how to inject values in it.

bidisha mukherjee
  • 715
  • 1
  • 10
  • 20
牛向辉
  • 271
  • 3
  • 7
  • Thank you! I was having exactly this problem, and this solves it. The weird situation is that Spring does check if the property exists (it throws an error when it's not defined in a properties file), yet it didn't use it to fill the variable. Now it does. – mcv May 31 '17 at 14:14
  • solved my issue as well, any idea why this happens ? – gaurav5430 Aug 01 '17 at 13:41
  • @gaurav5430 in short 'Dependency Injection'. You don't create bean objects using `new` operator instead you use the beans created by spring framework using `@Autowired` annotation. When spring application starts up it creates bean and set its fields, now if you don't use this bean and instead use your own object created using `new` operator, you will get null in the property variable. – Paramvir Singh Karwal Nov 20 '18 at 10:37
19

Make sure your application.properties file is under src/main/resources/application.properties. Is one way to go. Then add @PostConstruct as follows

Sample Application.properties

file.directory = somePlaceOverHere

Sample Java Class

@ComponentScan
public class PrintProperty {

  @Value("${file.directory}")
  private String fileDirectory;

  @PostConstruct
  public void print() {
    System.out.println(fileDirectory);
  }
}

Code above will print out "somePlaceOverhere"

JayC
  • 2,144
  • 8
  • 42
  • 77
  • 2
    Using `@PostConstruct` will initialise any fields that depend on the ones initialised by `@Value` annotation. Thanks – georger Apr 11 '18 at 17:13
  • 1
    After a lot of research BeanPostProcessors `@PostConstruct` annotation helped to resolve the issue. To read properties from in `@Configuration and @Value`. thanks. – Yash Aug 10 '18 at 14:00
8

I´d like to mention, that I used spring boot version 1.4.0 and since this version you can only write:

@Component
public class MongoConnection {

@Value("${spring.data.mongodb.host}")
private String mongoHost;

@Value("${spring.data.mongodb.port}")
private int mongoPort;

@Value("${spring.data.mongodb.database}")
private String mongoDB;
}

Then inject class whenever you want.

EDIT:

From nowadays I would use @ConfigurationProperties because you are able to inject property values in your POJOs. Keep hierarchical sort above your properties. Moreover, you can put validations above POJOs attributes and so on. Take a look at the link

Peter S.
  • 470
  • 1
  • 7
  • 17
2

To read the values from application.properties we need to just annotate our main class with @SpringBootApplication and the class where you are reading with @Component or variety of it. Below is the sample where I have read the values from application.properties and it is working fine when web service is invoked. If you deploy the same code as is and try to access from http://localhost:8080/hello you will get the value you have stored in application.properties for the key message.

package com.example;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {

    @Value("${message}")
    private String message;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @RequestMapping("/hello")
    String home() {
        return message;
    }

}

Try and let me know

rajadilipkolli
  • 3,475
  • 2
  • 26
  • 49
  • I tried that, but it didn't work. The properties get resolved in my main class with @SpringBootApplication annotation, but not in this class. – user6641655 Aug 22 '16 at 14:55
  • Try adding @Component annotation to your class and let me know what happened – rajadilipkolli Aug 22 '16 at 18:49
  • This code works fine as is for web app. I tried it. But, not works sometimes for standalone app. Not sure what are the reasons for it. – Pankaj Feb 17 '17 at 21:28
1

You haven't included package declarations in the OP but it is possible that neither @SpringBootApplication nor @ComponentScan are scanning for your @Component.

The @ComponentScan Javadoc states:

Either basePackageClasses or basePackages (or its alias value) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.

ISTR wasting a lot of time on this before and found it easiest to simply move my application class to the highest package in my app's package tree.

More recently I encountered a gotcha were the property was being read before the value insertion had been done. Jesse's answer helped as @PostConstruct seems to be the earliest you can read the inserted values, and of course you should let Spring call this.

Simon Gibbs
  • 4,737
  • 6
  • 50
  • 80
1

I had the similar issue and the above examples doesn't help me to read properties. I have posted the complete class which will help you to read properties values from application.properties file in SpringBoot application in the below link.

Spring Boot - Environment @Autowired throws NullPointerException

Nallamachu
  • 1,420
  • 18
  • 34
0

Your problem is that you need a static PropertySourcesPlaceholderConfigurer Bean definition in your configuration. I say static with emphasis, because I had a non-static one and it didn't work.

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}
Dormouse
  • 1,617
  • 1
  • 23
  • 33
0

I had the same issue get value for my property in my service class. I resolved it by using @ConfigurationProperties instead of @Value.

  1. create a class like this:
    import org.springframework.boot.context.properties.ConfigurationProperties;

    @ConfigurationProperties(prefix = "file")
    public class FileProperties {
        private String directory;

        public String getDirectory() {
            return directory;
        }

        public void setDirectory(String dir) {
            this.directory = dir;
        }
    }

  1. add the following to your BootApplication class:
    @EnableConfigurationProperties({
        FileProperties.class
    })
  1. Inject FileProperties to your PrintProperty class, then you can get hold of the property through the getter method.
John Wu
  • 1
  • 2