I want to return HTTPStatus code dynamically like 400, 400, 404 etc as per the response object error.
I was referred to this question - Programmatically change http response status using spring 3 restful but it did not help.
I have this Controller class with an @ExceptionHandler
method
@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseEntity<?> handleException(CustomException e) {
return new ResponseEntity<MyErrorResponse>(
new MyErrorResponse(e.getCode(), ExceptionUtility.getMessage(e.getMessage())),
ExceptionUtility.getHttpCode(e.getCode()));
}
ExceptionUtility
is a class where I have the two methods used above (getMessage
and getCode
).
public class ExceptionUtility {
public static String getMessage(String message) {
return message;
}
public static HttpStatus getHttpCode(String code) {
return HttpStatus.NOT_FOUND; //how to return status code dynamically here ?
}
}
I do not want to check in if condition and return the response code accordingly, Is there any other better approach to do this?
Your @ExceptionHandler
method needs two things:
(i) have an HttpServletResponse
parameter, so that you can set the response status code; and (ii) do not have the @ResponseStatus
annotation.
@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseEntity<?> handleException(HttpServletResponse resp, CustomException e) {
resp.setStatus(ExceptionUtility.getHttpCode(e.getCode()).value());
return new ResponseEntity<MyErrorResponse>(
new MyErrorResponse(e.getCode(), ExceptionUtility.getMessage(e.getMessage())),
ExceptionUtility.getHttpCode(e.getCode()));
}
I have used this kind of @ExceptionHandler
to handle NestedServletException
, which is an exception that Spring sometimes creates to wrap the "actual" exception that needs to be treated (code below). Note that the @ExceptionHandler
method can have both request and response objects as parameters, if you need them.
@ExceptionHandler(NestedServletException.class)
@ResponseBody
public Object handleNestedServletException(HttpServletRequest req, HttpServletResponse resp,
NestedServletException ex) {
Throwable cause = ex.getCause();
if (cause instanceof MyBusinessLogicException) {
resp.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
return createStructureForMyBusinessLogicException((MyBusinessLogicException) cause);
}
if (cause instanceof AuthenticationException) {
resp.setStatus(HttpStatus.UNAUTHORIZED.value());
} else if (cause instanceof AccessDeniedException) {
resp.setStatus(HttpStatus.FORBIDDEN.value());
} else {
resp.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
return createStructureForOtherErrors(req, cause.getMessage(), resp.getStatus());
}
You need to define different Exception handler for different Exception and then use @ResponseStatus
as below:
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler({ UnAuthorizedException.class })
public @ResponseBody ExceptionResponse unAuthorizedRequestException(final Exception exception) {
return response;
}
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler({ DuplicateDataException.class })
public @ResponseBody ExceptionResponse DuplicateDataRequestException(final Exception exception) {
return response;
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({ InvalidException.class })
public @ResponseBody ExceptionResponse handleInvalidException(final Exception exception) {
return response;
}
Here the InvalidException.class
, DuplicateDataException.class
etc are examples. You can define your custom Exceptions and throw them from controller layer. for example you can define a UserAlreadyExistsException
and return the HttpStatus.CONFLICT
error code from your exception handler.