Subin Chalil
Subin Chalil

Reputation: 3660

How to use a @Autowired bean inside a constructor?

Here is my class,

public class MyBusinessException extends RuntimeException {
    @Autowired
    private MessageSource messageSource;

    private String errorCode;

    private String messageInEnglish;

    public MyBusinessException(String errorCode){
       this.errorCode=errorCode;
       this.messageInEnglish=messageSource.getMessage(this.code,null, Locale.ENGLISH);
    }
}

This is an exception class.When I pass the errorCode as a parameter to constructor it should populate the error message,That`s what I am looking for.Infact I want to instantiate the class like this

throw new MyBusinessException("MY-ERROR-CODE");//want to initiate like this(only one argument for constructor)

How to achieve something like this?

All these I have tried so far:

  1. Constructor Autowiring.
  2. Using @PostConstruct

Upvotes: 3

Views: 3006

Answers (4)

davidxxx
davidxxx

Reputation: 131326

throw new MyBusinessException("MY-ERROR-CODE");//want to initiate like this(only one argument for constructor)

You cannot use @Autowired with objects that are not created by Spring.
I think that you should refactor your code to provide to MyBusinessException constructor all information that needs.
You don't need to couple it with Spring.

The logic that is Spring dependent :

@Autowired
private MessageSource messageSource; 
...
messageSource.getMessage(this.code,null, Locale.ENGLISH);

could be moved to a Spring bean that will create a fully initialized MyBusinessException instance.
Besides, messageSource.getMessage(this.code,null, Locale.ENGLISH) may be required for other exceptions. Moving it this logic in a specific class makes sense.

@Bean
public class ExceptionFactory{
   @Autowired
   private MessageSource messageSource; 

   public MyBusinessException createMyBusinessException(String errorCode){        
      return new MyBusinessException(errorCode, messageSource.getMessage(this.code,null, Locale.ENGLISH));        
  } 
}

You can note that createMyBusinessException() provides a simple API for the clients : they need to pass only the error code String to create the exception.
The MessageSource dependency is a implementation detail that they don't need to bother with.

For example, this is enough :

throw exceptionFactory.createMyBusinessException("MY-ERROR-CODE");

Upvotes: 5

Yannic Bürgmann
Yannic Bürgmann

Reputation: 6571

Dependency Injection does only work for instances that are created by Spring.

Since you manually initialize your exception you need to inject the MessageSource to the @Component throwing this exception.

Then you could either pass the MessageSource to the constructor of your MyBusinessException or get the message in the desired language and pass this message to the constructor.

@Component
public class MyComponentDoingBusinessLogic {

    private MessageSource messageSource;

    @Autowired
    public MyComponentDoingBusinessLogic(MessageSource messageSource) {
      this.messageSource = messageSource;
    }

    public void someBusinessLogic() {
      //Doing something
      if (errorState) {
        throw new MyBusinessException(yourErrorCode, messageSource);
      }
    }
}

Upvotes: 3

SeverityOne
SeverityOne

Reputation: 2691

You can't do it this way. An exception is constructed when it is thrown, which means that it won't get initialised by Spring. What you could do is to use a static method to get the current Spring application context, and get your bean from there.

Whether or not this is a clean solution is another issue, but you didn't ask about that.

Upvotes: 0

OhadR
OhadR

Reputation: 8839

You cannot use @Autowired inside the ctor, as it was not yet initializaed by Spring.

The right way to do so, is to implement InitializingBean, which is basically Spring's ctor, and there (afterPropertiesSet method) you can use your injected fields.

Upvotes: 1

Related Questions