3

In Spring boot and rest application, i have configured a exception handler as following. It works fine if an exception is thrown after request makes it to rest service.

The Rest api expects Content-Type of "application/json" and If I do not send that content-type header to the api, exception handler does not catch the exception. It prints following information in the log:

DEBUG [o.s.w.s.DispatcherServlet] DispatcherServlet with name 'dispatcherServlet' processing PUT request for [/app/v1.0/customers/customer/zones/zoneName.]
DEBUG [o.s.w.s.m.m.a.RequestMappingHandlerMapping] Looking up handler method for path /app/v1.0/customers/customer/zones/zoneName.
DEBUG [o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver] Resolving exception from handler [null]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/plain' not supported
DEBUG [o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver] Invoking @ExceptionHandler method: public final org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)
DEBUG [o.s.w.s.DispatcherServlet] Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
DEBUG [o.s.w.s.DispatcherServlet] Successfully completed request

Here's the exception handler class:

@ControllerAdvice
@RestController  
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler
{

    @ExceptionHandler(Exception.class)  
    public final ResponseEntity<java.lang.Object> handleException(Throwable ex,WebRequest req)
    {
        ErrorResponse errorResponse = null;
        if (ex instanceof ApiException)
        {
            errorResponse = new ErrorResponse((ApiException) ex);
        }
        else
        {
            logger.error(ex);
            errorResponse = new ErrorResponse();
            errorResponse.setCode(HttpCodes.HTTP_CODE_500);
            errorResponse.setError(ex.getMessage());
        }
        return new ResponseEntity<Object>(errorResponse,
                HttpStatus.valueOf(errorResponse.getCode()));

    }
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        Map<String, String> responseBody = new HashMap<String, String>();
        responseBody.put("path", request.getContextPath());
        responseBody.put("message",
                "The URL you have reached is not in service at this time (404).");
        return new ResponseEntity<Object>(responseBody, HttpStatus.NOT_FOUND);
    }
}

2 Answers 2

5

Your class will only catch errors raised from within a controller. The error you are seeing occurs before a controller is invoked, as Spring cannot find a controller to handle the request.

DEBUG [o.s.w.s.m.m.a.RequestMappingHandlerMapping] Looking up handler method for path /app/v1.0/customers/customer/zones/zoneName.
DEBUG [o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver] Resolving exception from handler [null]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/plain' not supported

Notice the handler is null.

You will also need to implement a HandlerExceptionResolver to handle that type of exception: http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers

See Spring exception handler outside controller for more details.

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

1 Comment

Thank you Adam. That provided really good pointers to find a working solution but it took me a while to fix it. Looks like spring does not like two exception handlers. I had ExceptionHandlerExceptionResolver and ResponseEntityExceptionHandler hence the exceptions were always going to ResponseEntityExceptionHandler. I removed ResponseEntity one and kept just the global ExceptionHandlerExceptionResolver and it worked like a charm.
2

Here's final solution:

@ControllerAdvice  
public class SpringExceptionHandler extends ExceptionHandlerExceptionResolver
{
    @ExceptionHandler(org.springframework.web.HttpMediaTypeNotSupportedException.class)
    public ResponseEntity<Object> handleControllerException(HttpMediaTypeNotSupportedException ex, WebRequest req)
    {
        ErrorResponse errorResponse = null;
        ex.printStackTrace();
        errorResponse = new ErrorResponse();
        errorResponse.setCode(HttpCodes.HTTP_CODE_INTERNAL_ERROR);
        errorResponse.setError(ex.getMessage());
        return new ResponseEntity<Object>(errorResponse,
            HttpStatus.valueOf(errorResponse.getCode()));
    }
}

Now I need to make some changes to make it work for all exceptions including controller thrown but that is for later. (Thanks Adam).

Important note: if there's both a global handler and an entity handler, spring ignores global handler.

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.