3

I have a Rest Controller in which I initialise a service like this :

class Config {
  @Value(${"number.of.books"})
  private final static String numberOfBooks;
}


class MyController  {

 private final Service myService = new ServiceImplementation(Config.numberOfBooks)

 public ResponseEntity methodA() { ... }

}

The numberOfBooks field has a initialisation value but when it's passed in the ServiceImplementation constructor it comes null.

I'm thinking I'm missing something obvious over here.

What is the mistake and which would be the best practice to inject a value from a property file into a constructor?

Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
rodor
  • 53
  • 1
  • 5
  • 2
    It's `@Value("${number.of.books}")`, also I don't think you can declare as final like that. – baao Jul 18 '17 at 17:54
  • Updated the snippet, from the syntax point of view the code is correct in the IDE, as the numberOfBooks field is initialized with the value from the property files. It's the constructor that reads it as null. – rodor Jul 18 '17 at 18:10
  • I guess the problem is the initialization order. If you remove the static keyword from the field and inject the Config class in MyController, it probably works. – dunni Jul 18 '17 at 18:14
  • The code isn't correct. You are trying to use a private field which won't work, and you can't declare a property that isn't initialized as final – baao Jul 18 '17 at 18:37
  • @baao You can declare a property `final` as long as it's set in the constructor. `static final` doesn't make sense, though. – Christopher Schneider Jul 18 '17 at 19:06
  • True, but OP doesn't set it in the constructor.. @ChristopherSchneider – baao Jul 18 '17 at 19:07
  • https://stackoverflow.com/a/4204175/5229041 - this answer is what you're looking for – maydawn Jul 18 '17 at 19:42

2 Answers2

2

I recommend you to directly inject numberOfBooks in your ServiceImplementation, as follows:

public class ServiceImplementation implements Service {

  @Value("${number.of.books}")
  private String numberOfBooks;

}

Otherwise use setter injection for static variables, as follows:

@Component
class Config {

 public static String numberOfBooks;

 @Value("${number.of.books}")
 public void setNumberOfBooks(String numberOfBooks) {
    numberOfBooks = numberOfBooks;
 }
}
Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
2

After studying a little I've found out that the dependency injection happens after the constructor has been called. This being said the approach used was to use Autowired on my services constructor.

class ServiceImplementation implements Service {

private final String numberOfBooks;

@Autowired
private ServiceImplementation(Config config) {
this.numberOfBooks = config.getNumberOfBooks();
}

}

In this way Spring creates the dependency tree and makes sure that Config is not null when injected.

rodor
  • 53
  • 1
  • 5