10

I have a Spring controller annotated with @RestController and it is returning JSON. I also have a class annotated with @ControllerAdvice with @ExceptionHandlers related to some custom exceptions. I am using Tomcat to serve this RESTful API. I'd like to have any non-custom exception such as one coming from a 3rd party library or a NullPointerException be caught and returned with status 500 - Internal Server Error as JSON with a message instead of an HTML page showing the error.

If I use an @ExceptionHandler(Exception.class) in the controller advice it takes over all of Spring exceptions like MissingPathVariableException.class, which is not ideal. I've tried extending Spring's ResponseEntityExceptionHandler but this class is not annotated with @ResponseBody so does not return JSON.

  1. How do you return JSON for uncaught and unknown exceptions (ones you can't plan for) in a Spring RESTful API without influencing Spring's internals?
  2. How can I turn off returning HTML entirely and ensure only JSON responses no matter whether the request has an exception or not?
dukethrash
  • 1,449
  • 4
  • 15
  • 25

2 Answers2

13

For returning JSON on uncaught exceptions you can use this code:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

@ControllerAdvice  
@RestController
public class GlobalExceptionHandler {

    private class JsonResponse {
        String message;

        public JsonResponse() {
        }

        public JsonResponse(String message) {
            super();
            this.message = message;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }       
    }

    @ExceptionHandler(value = Exception.class)  
    public ResponseEntity<JsonResponse> handleException(Exception e) {
        return new ResponseEntity<JsonResponse>(new JsonResponse(e.getMessage()), HttpStatus.BAD_REQUEST);
    }

}

JSON result if exception is throwing:

{
    "message": "Something wrong!"
}

You can use this link for more detailed information about Spring exception handling (with code examples).

Maksym
  • 2,650
  • 3
  • 32
  • 50
  • 2
    How can we implement a similar class for Spring 3.1.4? – user679526 Mar 28 '18 at 19:00
  • This topic can help you: https://stackoverflow.com/questions/6742324/exception-handler-in-spring-mvc – Maksym Mar 28 '18 at 19:59
  • This code was swallowing all the HTTPStatus codes from all my apis until I replaced the guts with `@ExceptionHandler(value = Exception.class) public ResponseEntity handleException(Exception e) { HttpStatus status = HttpStatus.BAD_REQUEST; ResponseStatus resp = AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class); if (resp != null) { status = resp.code(); } return new ResponseEntity<>(new JsonResponse(e.getMessage()), status); }` – Paul Tomblin Aug 10 '21 at 19:11
0

HttpEntity represents an HTTP request or response consists of headers and body.

// Only talks about body & headers, but doesn't talk about status code
public HttpEntity(T body, MultiValueMap<String,String> headers)

ResponseEntity extends HttpEntity but also adds a Http status code.

// i.e ResponseEntity = HttpEntity + StatusCode
public ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus statusCode)

Hence used to fully configure the HTTP response.

If you have a look at constructor of ResponseEntity you will see first parameter as body, i.e exactly where you can pass the object you want as body of http response when exception arrives

Ziaullhaq Savanur
  • 1,848
  • 2
  • 17
  • 20