'How to get response in JSON format using @ExceptionHandler in Spring MVC

I am new to this @ExceptionHandler. I need to return response in JSON format if there is any exception. My code is returning response in JSON format if the operation is successful. But when any exception is thrown it is return HTML response as I have used @ExceptionHandler.

Value and reason in @ResponseStatus is coming properly but in HTML. How can I can change it to a JSON response? Please help.

In my controller class i have this methods:

@RequestMapping(value = "/savePoints", method = RequestMethod.POST, consumes = "application/json", produces = "application/json;charset=UTF-8")
public @ResponseBody
GenericResponseVO<TestResponseVO> saveScore(
        @RequestBody(required = true) GenericRequestVO<TestVO> testVO) {
    UserContext userCtx = new UserContext();
    userCtx.setAppId("appId");
    return gameHandler.handle(userCtx, testVO);
}

Exception handling method:

@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Error in the process")
@ExceptionHandler(Exception.class)
public void handleAllOtherException() {

}


Solution 1:[1]

You can annotate the handler method with @ResponseBody and return any object you want and it should be serialized to JSON (depending on your configuration of course). For instance:

public class Error {
    private String message;
    // Constructors, getters, setters, other properties ...
}

@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Error handleValidationException(MethodArgumentNotValidException e) {
    // Optionally do additional things with the exception, for example map
    // individual field errors (from e.getBindingResult()) to the Error object
    return new Error("Invalid data");
}

which should produce response with HTTP 400 code and following body:

{
    "message": "Invalid data"
}

Also see Spring JavaDoc for @ExceptionHandler which lists possible return types, one of which is:

@ResponseBody annotated methods (Servlet-only) to set the response content. The return value will be converted to the response stream using message converters.

Solution 2:[2]

Replace

@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Error in the process")

by

@ResponseStatus(value = HttpStatus.NOT_FOUND)

the 'reason' attribute force html render! I've waste 1 day on that.....

Solution 3:[3]

ResponseEntity class will serialize you JSON response by default here and throw RuntimeException wherever you want to in application

throw RuntimeException("Bad Request")

Write GlobalExceptionHandler class

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private class JsonResponse {
        String message;
        int httpStatus ;

        public JsonResponse() {
        }

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

        public String getMessage() {
            return message;
        }

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

        public int getHttpStatus() {
            return httpStatus;
        }

        public void setHttpStatus(int httpStatus) {
            this.httpStatus = httpStatus;
        }
        
    }
    
    @ExceptionHandler({ RuntimeException.class })
    @ResponseBody
    public ResponseEntity<JsonResponse> handleRuntimeException(
    Exception ex, WebRequest request) {
      return new ResponseEntity<JsonResponse>(
              new JsonResponse(ex.getMessage(), 400 ), new HttpHeaders(), HttpStatus.BAD_REQUEST);
    }

}

Output:

{
    "message": "Bad Request",
    "httpStatus": 400
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Karthikeyan
Solution 3