aycanadal
aycanadal

Reputation: 1146

Spring data rest i18n domain exceptions

I have a sdr project where I do some basic validation in entity setters and throw a domain exception if model is invalid. I can not get a message source inside the exception so that I can localize the business exception message. Custom exception class I have tried is:

@ResponseStatus(org.springframework.http.HttpStatus.CONFLICT)
public class DoublePriceException extends Exception {

    @Autowired
    static ReloadableResourceBundleMessageSource messageSource;

    private static final long serialVersionUID = 1L;

    public DoublePriceException(OrderItem orderItem) {

        super(String.format(
                messageSource.getMessage("exception.doublePricedItem", null, LocaleContextHolder.getLocale()),
                orderItem.name));

    }

}

And how I try to throw this mofo is:

public void setPrices(List<Price> prices) throws DoublePriceException {

        for (Price price : prices) {

            List<Price> itemsPrices = prices.stream().filter(it -> price.item.equals(it.item)).collect(Collectors.toList());

            if(itemsPrices.size() > 1)
                throw new DoublePriceException(itemsPrices.get(0).item);

        }

        this.prices = prices;

    }

messageSource is always null. Is what I am trying not achievable?

Upvotes: 0

Views: 477

Answers (2)

aycanadal
aycanadal

Reputation: 1146

Best I could come up with is catching the HttpMessageNotReadableException and calling getMostSpecificCause() like the following:

@RestControllerAdvice
public class ExceptionHandlingAdvice {

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<Object> onException(HttpMessageNotReadableException ex, WebRequest request) {

        Locale locale = request.getLocale();
        Throwable cause = ex.getMostSpecificCause();
        String message = cause.getMessage();

        if (cause instanceof MultiplePriceException) {

            message = messageSource.getMessage("exception.multiple.price",
                    new Object[] { ((MultiplePriceException) cause).orderItem.name }, locale);

        }

        return new ResponseEntity(Collections.singletonMap("error", message), new HttpHeaders(),
                HttpStatus.BAD_REQUEST);

    }
}

Upvotes: 0

Alan Hay
Alan Hay

Reputation: 23226

DoublePriceException is obviously not a Spring managed Bean so that is not going to work.

You can register a Spring ControllerAdvice in your application that handles the exception and generates a suitable response.

/**
 * Spring MVC @link {@link ControllerAdvice} which 
 * is applied to all Controllers and which will handle 
 * conversion of exceptions to an appropriate JSON response.
 */
@ControllerAdvice
public class ErrorHandlingAdvice
{
  /**
   * Handles a @DoublePriceException 
   *
   * @param ex the DoublePriceException 
   * 
   * @return JSON String with the error details.
   */
  @ExceptionHandler(DoublePriceException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ResponseBody
  public Object processValidationError(DoublePriceException  ex)
  {
    //return suitable representation of the error message
    //e.g. return Collections.singletonMap("error", "my error message");
  }
}

Placing the above in a package scanned by the Spring framework should be enough to have it detected and applied.

Upvotes: 1

Related Questions