103

Shown below is a snippet of code where I try and reference my ApplicationProperties bean. When I reference it from the constructor it is null, but when referenced from another method it is fine. Up until now I have not had no problem using this autowired bean in other classes. But this is the first time I have tried to use it in the constructor of another class.

In the code snippet below applicationProperties is null when called from the constructor but when referenced in the convert method it is not. What am I missing

@Component
public class DocumentManager implements IDocumentManager {

  private Log logger = LogFactory.getLog(this.getClass());
  private OfficeManager officeManager = null;
  private ConverterService converterService = null;

  @Autowired
  private IApplicationProperties applicationProperties;


  // If I try and use the Autowired applicationProperties bean in the constructor
  // it is null ?

  public DocumentManager() {
  startOOServer();
  }

  private void startOOServer() {
    if (applicationProperties != null) {
      if (applicationProperties.getStartOOServer()) {
        try {
          if (this.officeManager == null) {
            this.officeManager = new DefaultOfficeManagerConfiguration()
              .buildOfficeManager();
            this.officeManager.start();
            this.converterService = new ConverterService(this.officeManager);
          }
        } catch (Throwable e){
          logger.error(e);  
        }
      }
    }
  }

  public byte[] convert(byte[] inputData, String sourceExtension, String targetExtension) {
    byte[] result = null;

    startOOServer();
    ...

Below is s snippet from ApplicationProperties ...

@Component
public class ApplicationProperties implements IApplicationProperties {

  /* Use the appProperties bean defined in WEB-INF/applicationContext.xml
   * which in turn uses resources/server.properties
   */
  @Resource(name="appProperties")
  private Properties appProperties;

  public Boolean getStartOOServer() {
    String val = appProperties.getProperty("startOOServer", "false");
    if( val == null ) return false;
    val = val.trim();
    return val.equalsIgnoreCase("true") || val.equalsIgnoreCase("on") || val.equalsIgnoreCase("yes");
  }
hairyone
  • 1,033
  • 2
  • 7
  • 4

3 Answers3

197

Autowiring (link from Dunes comment) happens after the construction of an object. Therefore they will not be set until after the constructor has completed.

If you need to run some initialization code, you should be able to pull the code in the constructor into a method, and annotate that method with @PostConstruct.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
  • 3
    As it says in the docs -- http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/factory/annotation/Autowired.html – Dunes Jun 13 '11 at 20:38
  • Thanks for the link, I will add it to the answer for easy finding. – nicholas.hauschild Jun 13 '11 at 20:39
  • 3
    Thank you, I had yet to come across the crucial statement "Fields are injected right after construction of a bean...". I have tried the @PostConstruct annotation and it is exactly what I needed. – hairyone Jun 13 '11 at 20:59
  • would be also nice to post a link about @PostConstruct http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s11.html – Timofey Apr 12 '13 at 10:54
  • @Tim Thanks! I updated the answers link to the Spring 3.2 version, and I also added a Spring 3.2 version of your link. – nicholas.hauschild Apr 12 '13 at 13:48
58

To have dependencies injected at construction time you need to have your constructor marked with the @Autowired annoation like so.

@Autowired
public DocumentManager(IApplicationProperties applicationProperties) {
  this.applicationProperties = applicationProperties;
  startOOServer();
}
mR_fr0g
  • 8,462
  • 7
  • 39
  • 54
  • 2
    Actually I thinks this should be the preferred answer. The constructor based dependency injection approach is very well suited for mandatory components. Using this approach the spring framework will also be able to detect cyclic dependenies on the components (as in A depends on B, B depends on C, C depends on A). The injection style using setters or autowired fields is able to inject not fully initialized beans into your field making things a bit more messy. – Seakayone Jan 11 '16 at 08:49
3

Yes, both answers are correct.

To be honest, this problem is actually similar to the post Why is my Spring @Autowired field null? .

The root cause of the error can be explained in the Spring reference doc (Autowired) , as follow:

Autowired Fields

Fields are injected right after construction of a bean, before any config methods are invoked.

But the real reason behind this statement in Spring doc is the Lifecycle of Bean in Spring. This is part of Spring's design philosophy.

This is Spring Bean Lifecycle Overview: enter image description here Bean needs to be initialized first before it can be injected with properties such as field. This is how beans are designed, so this is the real reason.

I hope this answer is helpful to you!

zhaocy
  • 72
  • 5