3

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
2
  • what is happening when you do new MyBusinessException(...) now? Commented Jan 29, 2018 at 12:26
  • why would you do that? by just storing the errorcode you have all you need Commented Jan 29, 2018 at 12:26

4 Answers 4

5

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");
Sign up to request clarification or add additional context in comments.

2 Comments

Like your solution since you have to write the code to find the message only one time instead of n-times for every instantiation of MyBusinessException
Thank you. In your code, the statements to find the message are also performed a single time : in MyBusinessException constructor. The advantages of the current solution are rather : 1) separation of concerns : messageSource.getMessage(this.code,null, Locale.ENGLISH) may be required for other exceptions. Moving it this logic in a specific class makes sense. 2) Simplified API for the client : you don't need to pass at each time two parameters to create the exception. Just the error code string is enough.
3

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);
      }
    }
}

3 Comments

How are you going to initialise anything if the exception isn't created by Spring?
added a small sample to make more clear what i described
@Yannic Klem Your solution is valid and not so bad at all :)
1

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.

1 Comment

This should probably be marked as the correct answer.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.