Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throw an exception back in JSON in Spring Boot

I have a Request Mapping -

  @RequestMapping("/fetchErrorMessages")
  public @ResponseBody int fetchErrorMessages(@RequestParam("startTime") String startTime,@RequestParam("endTime") String endTime) throws Exception
  {
      if(SanityChecker.checkDateSanity(startTime)&&SanityChecker.checkDateSanity(endTime))
      {
          return 0;
      }
      else
      {
          throw new NotFoundException("Datetime is invalid");
      }
  }

If the startTime and endTime are invalid, I want to throw a 500 error but return the exception string in JSON. However, I get a HTML Page instead saying

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Wed Dec 20 10:49:37 IST 2017
There was an unexpected error (type=Internal Server Error, status=500).
Datetime is invalid

I instead wanted to return 500 with a JSON

{"error":"Date time format is invalid"}

How do I go about this?

like image 405
Prateek Narendra Avatar asked Dec 20 '17 05:12

Prateek Narendra


4 Answers

Suppose you have a custom Exception class NotFoundException and its implementations something like this:

public class NotFoundException extends Exception {

    private int errorCode;
    private String errorMessage;

    public NotFoundException(Throwable throwable) {
        super(throwable);
    }

    public NotFoundException(String msg, Throwable throwable) {
        super(msg, throwable);
    }

    public NotFoundException(String msg) {
        super(msg);
    }

    public NotFoundException(String message, int errorCode) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = message;
    }


    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    @Override
    public String toString() {
        return this.errorCode + " : " + this.getErrorMessage();
    }
}

Now you want to throw some exception from controller. If you throw a exception then you must catch it from a standard Error Handler class, say for example in spring they provide @ControllerAdvice annotation to apply to make a class Standard Error Handler. When it is applied to a class then this spring component (I mean the class you annotated) can catch any exception thrown from controller. But We need to map exception class with proper method. So we defined a method with your exception NotFoundException handler something like below.

@ControllerAdvice
public class RestErrorHandler {

    @ExceptionHandler(NotFoundException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Object processValidationError(NotFoundException ex) {
        String result = ex.getErrorMessage();
        System.out.println("###########"+result);
        return ex;
    }
}

You want to sent http status to internal server error(500), so here we used @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR). Since you used Spring-boot so you do not need to make a json string except a simple annotation @ResponseBody can do that for you automagically.

like image 93
Ataur Rahman Munna Avatar answered Nov 03 '22 07:11

Ataur Rahman Munna


Create a custom exception.

public class SecurityException extends RuntimeException {

    private static final long serialVersionUID = -7806029002430564887L;

    private String message;

    public SecurityException() {
    }

    public SecurityException(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

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

}

Create a custom response entity.

public class SecurityResponse {

    private String error;

    public SecurityResponse() {

    }

    public SecurityResponse(String error) {
        this.error = error;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

}

Create a ControllerAdvice with ExceptionHandler for custom exception, it will handle the custom exception, populate and return the custom response as below.

@ControllerAdvice
public class SecurityControllerAdvice {

    @ExceptionHandler(SecurityException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public SecurityResponse handleSecurityException(SecurityException se) {
        SecurityResponse response = new SecurityResponse(se.getMessage());
        return response;
    }
}

Throw the custom exception based on your condition.

throw new SecurityException("Date time format is invalid");

Now run and test you app. E.G. :

enter image description here

like image 44
Neeraj Benjwal Avatar answered Nov 03 '22 06:11

Neeraj Benjwal


you can create NotFoundException class with @ResponseStatus annotation like below:

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class NotFoundException extends RuntimeException {
   public NotFoundException() {
   }

   public NotFoundException(String message) {
    super(message);
   }

}
like image 2
hiren Avatar answered Nov 03 '22 07:11

hiren


Javax has a interface name as ExceptionMapper. Please refer the below code snippet, For every RuntimeException in your application it will map it to a Json Response entity.

public class RuntimeExceptionMapper implements ExceptionMapper <RuntimeException> {

@Override
public Response toResponse(RuntimeException exception) {
    ErrorResponse errorResponse = new ErrorResponse();
    errorResponse.setMessage(exception.getMessage);
    if (exception== null) {
        logger.error("Exception Details Not found");            
    } else {
        return Response.status(Status.INTERNAL_SERVER_ERROR)
            .entity(errorResponse )
                .type(MediaType.APPLICATION_JSON)
                    .header("trace-id", "1234").build();
    }


}

}

like image 1
Mohit Sharma Avatar answered Nov 03 '22 06:11

Mohit Sharma