Alex Alex - 2 months ago 9
reST (reStructuredText) Question

Spring Boot custom exception within an Rest Service

I have defined a global exception handling in my Spring Boot based Rest service:

@ControllerAdvice
public class GlobalExceptionController {

private final Logger LOG = LoggerFactory.getLogger(getClass());

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Internal application error")
@ExceptionHandler({ServiceException.class})
@ResponseBody
public ServiceException serviceError(ServiceException e) {
LOG.error("{}: {}", e.getErrorCode(), e.getMessage());
return e;
}
}


and a custom ServiceException:

public class ServiceException extends RuntimeException {

private static final long serialVersionUID = -6502596312985405760L;

private String errorCode;

public ServiceException(String message, String errorCode, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}

// other constructors, getter and setters omitted
}


so far so good, when an exception is fired the controller works as it should and respond with:

{
"timestamp": 1413883870237,
"status": 500,
"error": "Internal Server Error",
"exception": "org.example.ServiceException",
"message": "somthing goes wrong",
"path": "/index"
}


but the field errorCode isn't shown in the JSON response.

So how can I define a custom exception response in my application.

Answer Source

Spring Boot uses an implementation of ErrorAttributes to populate the Map that's rendered as JSON. By default, an instance of DefaultErrorAttributes is used. To include your custom errorCode you'll need to provide a custom ErrorAttributes implementation that knows about ServiceException and its error code. This custom implementation should be an a @Bean in your configuration.

One approach would be to sub-class DefaultErrorAttributes:

@Bean
public ErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes() {

        @Override
        public Map<String, Object> getErrorAttributes(
                RequestAttributes requestAttributes,
                boolean includeStackTrace) {
            Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
            Throwable error = getError(requestAttributes);
            if (error instanceof ServiceException) {
                errorAttributes.put("errorCode", ((ServiceException)error).getErrorCode());
            }
            return errorAttributes;
        }

    };
}