7

I am not able to override default spring boot error response in REST api. I have following code

@ControllerAdvice
@Controller
class ExceptionHandlerCtrl {

    @ResponseStatus(value=HttpStatus.UNPROCESSABLE_ENTITY, reason="Invalid data")
    @ExceptionHandler(BusinessValidationException.class)
    @ResponseBody
    public ResponseEntity<BusinessValidationErrorVO> handleBusinessValidationException(BusinessValidationException exception){
        BusinessValidationErrorVO vo = new BusinessValidationErrorVO()
        vo.errors = exception.validationException
        vo.msg = exception.message
        def result =  new ResponseEntity<>(vo, HttpStatus.UNPROCESSABLE_ENTITY);
        result

    }

Then in my REST api I am throwing this BusinessValidationException. This handler is called (I can see it in debugger) however I still got default spring boot REST error message. Is there a way to override and use default only as fallback? Spring Boot version 1.3.2 with groovy. Best Regards

3 Answers 3

9

Remove @ResponseStatus from your method. It creates an undesirable side effect and you don't need it, since you are setting HttpStatus.UNPROCESSABLE_ENTITY in your ResponseEntity.

From the JavaDoc on ResponseStatus:

Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.

With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of @ResponseStatus altogether.

Sign up to request clarification or add additional context in comments.

Comments

1

I suggest you to read this question: Spring Boot REST service exception handling

There you can find some examples that explain how to combine ErrorController/ ControllerAdvice in order to catch any exception.

In particular check this answer:

https://stackoverflow.com/a/28903217/379906

You should probably remove the annotation @ResponseStatus from the method handleBusinessValidationException.

Another way that you have to rewrite the default error message is using a controller with the annotation @RequestMapping("/error"). The controller must implement the ErrorController interface.

This is the error controller that I use in my app.

@RestController
@RequestMapping("/error")
public class RestErrorController implements ErrorController
{
    private final ErrorAttributes errorAttributes;

    @Autowired
    public MatemoErrorController(ErrorAttributes errorAttributes) {
        Assert.notNull(errorAttributes, "ErrorAttributes must not be  null");
    this.errorAttributes = errorAttributes;
  }

@Override
public String getErrorPath() {
    return "/error";
}

@RequestMapping
public Map<String, Object> error(HttpServletRequest aRequest) {

    return getErrorAttributes(aRequest, getTraceParameter(aRequest));
}

private boolean getTraceParameter(HttpServletRequest request) {
    String parameter = request.getParameter("trace");
    if (parameter == null) {
        return false;
    }
    return !"false".equals(parameter.toLowerCase());
}

private Map<String, Object> getErrorAttributes(HttpServletRequest  aRequest, boolean includeStackTrace)
{
    RequestAttributes requestAttributes = new  ServletRequestAttributes(aRequest);
    return errorAttributes.getErrorAttributes(requestAttributes,  includeStackTrace);
}  }

Comments

0

For spring boot 3 I did the following since all other options I searched on the Internet did not result in success. First step was to disable auto configuration:

@SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})

Then I had to create something like this:

@RestControllerAdvice
public class RestResponseEntityExceptionHandler{


    /*
    what to handle watch here:
org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
     */
    @ExceptionHandler({ Exception.class })
    public ResponseEntity<Object> handleException(
            Exception ex, WebRequest request) throws Exception {

        switch (ex){
            case HttpMessageNotReadableException exception -> {
                return new ResponseEntity<>("Json input could not be parsed", HttpStatus.BAD_REQUEST);

            }
            default -> {
                return new ResponseEntity<>("Internal server error", HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }

    }


}

I took the Java 17 pattern matching approach to make a more readable list of exception handling

Hope it helps someone because the defaults were pretty bad for what I wanted to do. Also had to introduce I18n which is almost impossible with vanila spring boot.

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.