0

I have a very simple configuration and a big confusion that I need help resolving.

I have a BaseController which is annotated with @RestController. In this class I have a method that returns a String and is annotated with @GetMapping. I am reading properties file from it and displaying the application value. Till here, all works GOOD. Below are my files,

@RestController
public class BaseController {

    @Autowired
    Environment env;

    @GetMapping("/hello")
    public String hello() {
        String myAppName = env.getProperty("spring.application.name");
        return "From Controller -> " + myAppName;
    }
}

My application.properties file,

server.servlet.context-path=/BootEnv
server.port=8085
spring.application.name=EnvironmentAPITester

When I hit,

http://localhost:8085/BootEnv/hello

, I get proper response like below,

From Controller -> EnvironmentAPITester

Here in code, Environment variable is org.springframework.core.env.Environment;

All is GOOD till here.

Now I have created a new @Configuration class named ApplicationConfig. I want to read the properties file from that class as well and return the values. So below are the changes I did,

@RestController
public class BaseController {

    @Autowired
    Environment env;

    @GetMapping("/hello")
    public String hello() {
        String myAppName = env.getProperty("spring.application.name");
        return "From Controller -> " + myAppName;
    }

    @GetMapping("/helloConf")
    public String getDetails() {
        ApplicationConfig conf = new ApplicationConfig();
        String fromConfig = conf.details();
        return "From Config -> "+fromConfig;
    }
}

And the class below,

@Configuration
public class ApplicationConfig{

    @Autowired
    Environment env;

    public String details() {
        return env.getProperty("spring.application.name");
    }
}

Now when I hit,

http://localhost:8085/BootEnv/helloConf

I get a null pointer exception as the Environment variable is null and does NOT get auto configured. HOW? And WHY?

After googling, I came to a solution which asked me to implement EnvironmentAware interface and set the Environment variable that way. So below are the changes I had to make to my ApplicationConfig class,

@Configuration
public class ApplicationConfig implements EnvironmentAware{

    @Autowired
    Environment env;

    public String details() {
        return env.getProperty("spring.application.name");
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;     
    }
}

After doing this also, it still gave me null pointer exception for the same Environment variable value. Then I figured out that not only I had to remove the @Autowire annotation but I ALSO needed to make that variable static to make it work. So when I do,

//@Autowired
static Environment env;

It works perfectly. And when I hit,

http://localhost:8085/BootEnv/helloConf

I get proper response,

From Config -> EnvironmentAPITester

The confusion is WHY do I need to make it static so that it fills the value? Why the EnvironmentAware implementation can't set the Environment variable while it is still @Autowired?

And why in the first place, @Autowired does not fill the Environment variable when the class ApplicationConfig class is marked with @Configuration annotation? Even if I change this class annotation to @Service or @Repository or @Component the same issue persists of failing to@Autowire the Environment variable. How come?

I know it's a long post. But any clarification on this is highly appreciated as I am having hard time understanding this.

Thanks for your help in advance.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
WebNoob
  • 237
  • 6
  • 16
  • You are creating a new instance of `ApplicationConfig` yourself. Spring doesn't know that and doesn't do any injection. – M. Deinum Sep 03 '18 at 11:42
  • @M.Deinum Thanks for the link. I now understand that I will have to Autowire the Config class itself in controller and it works perfect. But the other question is still unanswered. Suppose somehow I need to use the **new ApplicationConfig();** and implement the EnvironmentAware interface. In that case, WHY do I need to make the Environment variable as STATIC to make it to work? What is the need to make it STATIC? Why without static it gives the same nullpointer exception? Any idea or clarification on that? Thanks. – WebNoob Sep 04 '18 at 09:48
  • 1
    Read the link. It works because you now have 2 instances (one managed by spring the other newly created) and due to the `static` nature (class level!) it works because you have 2 instances of a single class. That is just how `static` works. You made it "work" but actually it is more of hack to make something that doesn't work "work". – M. Deinum Sep 04 '18 at 09:49
  • @M.Deinum Thanks for the response, I got it how static worked. But if making it static is a hack, what should be the ideal way to implement it? I mean, if I want to use **new ApplicationConfig();** and don't want to go for static the way I did, how to implement it? Using @Configurable? That seems a bit complex and lengthy too considering all the aspectJ jars and instrument jar needed to get it to work. Any other simpler workaround if possible? – WebNoob Sep 04 '18 at 11:16
  • No there isn't another workaround. Either use the spring managed instance or intercept the object creation with Aspectj. those are your 2 options. – M. Deinum Sep 04 '18 at 11:18
  • Alright, got it. Thanks for all the help. – WebNoob Sep 04 '18 at 11:19

0 Answers0