Rakesh Goyal
Rakesh Goyal

Reputation: 3231

Custom Spring Exceptions with bind variables

I want to create a custom business exception:

public class BusinessException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public BusinessException(String msg) {

        super(msg);
    }

    public BusinessException(String msg, Object[] params) {

        //Not sure how to pass params to @ExceptionHandler

        super(msg);
    }

}

and use it in my spring mvc rest controller:

@RequestMapping(value = "/{code}", method = RequestMethod.GET)
    public @ResponseBody
    String getState(@PathVariable String code) throws Exception {
        String result;
        if (code.equals("KL")) {
            result = "Kerala";
        } else {

            throw new BusinessException("NotAValidStateCode",new Object[]{code});
        }
        return result;
    }

I am handling all the businessException using common exception handler:

@ControllerAdvice
public class RestErrorHandler {

    private static final Logger LOGGER = LoggerFactory
            .getLogger(RestErrorHandler.class);

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public String handleException(

    Exception ex) {

        Object[] args=null; // Not sure how do I get the args from custom BusinessException

        String message = messageSource.getMessage(ex.getLocalizedMessage(),
                args, LocaleContextHolder.getLocale());

        LOGGER.debug("Inside Handle Exception:" + message);

        return message;

    }

}

Now my problem is , I want to read the message text from messages property file where some of the keys are expecting run time bind variables e.g.

NotAValidStateCode= Not a valid state code ({0})

I am not sure how do I pass these arguments to handleException Method of RestErrorHandler.

Upvotes: 1

Views: 2890

Answers (2)

Pavel Horal
Pavel Horal

Reputation: 18194

This is simple as you have already done all the "heavy lifting":

public class BusinessException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    private final Object[] params;

    public BusinessException(String msg, Object[] params) {
        super(msg);
        this.params = params;
    }

    public Object[] getParams() {
        return params;
    }

}

@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleException(BusinessException ex) {
    String message = messageSource.getMessage(ex.getMessage(),
            ex.getParams(), LocaleContextHolder.getLocale());
    LOGGER.debug("Inside Handle Exception:" + message);
    return message;
}

Upvotes: 1

Andy Wilkinson
Andy Wilkinson

Reputation: 116101

I would recommend encapsulating everything that you need to create the error message in BusinessException. You're already passing in code as part of the array of params. Either expose that whole array with a getParams() method, or (and this is the approach I would take) add a code field and getCode() method to BusinessException and add a code argument to BusinessException's constructor. You can then update handleException to take a BusinessException rather than an Exception and use getCode() when creating the arguments used to create the message.

Upvotes: 0

Related Questions