Hi Spring team,
I am extending ResponseEntityExceptionHandler to implement a global exception handler, and I come across these two problems.
- Return ResponseEntity statement seems not working without @ResponseStatus for built-in exception types.
For example, I throw an IllegalArgumentException in controller when a param fails validation. Then I catch the exception in GlobalExceptionHandler
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
protected ResponseEntity<Result> illegalParamErrorHandler(IllegalArgumentException ex) {
return new ResponseEntity<>(
ResultUtil.error(ErrorCodeEnum.ERROR_CODE_BAD_REQUEST, ex.getMessage()),
HttpStatus.BAD_REQUEST
);
}
}
The response code is still 500 Internal Error instead of assigned HttpStatus.BAD_REQUEST
as expected.
Then I tried to add @ResponseStatus
annotation and it worked. The response code becomes 400.
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) // <--------- add this line
protected ResponseEntity<Result> illegalParamErrorHandler(IllegalArgumentException ex) {
return new ResponseEntity<>(
ResultUtil.error(ErrorCodeEnum.ERROR_CODE_BAD_REQUEST, ex.getMessage()),
HttpStatus.BAD_REQUEST
);
}
}
[Question] Just to confirm, I am not sure is this an expected behavior?
- Is conditional response status code mapping supported for custom Exception?
For this case, I have a custom Exception class holding some detailed error info:
public class CustomException extends RuntimeException {
private final CustomFaultInfo faultInfo;
// getters and setters
}
public class CustomFaultInfo {
private String code;
private String message;
// getters and setters
}
Then I intercept this exception in GlobalExceptionHandler. What I tried to do is to read the detailed error code info in my CustomException object and decide which status code to return. So here comes the code:
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(CustomException.class)
protected ResponseEntity<Result> CustomErrorHandler(CustomException ex) {
CustomFaultInfo faultInfo = ex.getCustomFaultInfo();
if (faultInfo != null) {
String errorCode = faultInfo.getCode();
if (errorCode.equals("400")) {
return new ResponseEntity<Object>(
ResultUtil.error(ErrorCodeEnum.ERROR_CODE_BAD_REQUEST, ex.getMessage()),
HttpStatus.BAD_REQUEST
);
}
if (errorCode.equals("404")) {
return new ResponseEntity<Object>(
ResultUtil.error(ErrorCodeEnum.ERROR_CODE_NOT_FOUND, ex.getMessage()),
HttpStatus.NOT_FOUND
);
}
}
}
}
This code does not work as expected. When faultInfo.getCode() == 400
it returns a status code of 400, which is correct. However when faultInfo.getCode() == 404
it still returns a status code 400 instead of 404.
Unfortunately in this case I cannot use the @ResponseStatus
annotation as a workaround either.
[Question] Is there a way to support such scenario?
I did some digging both on Google, SO and source code, yet found few information that helps. Could you please help explain this a bit? Really appreciated.
Best regards, Kevin
Comment From: rstoyanchev
None of this makes sense based on the description alone. The one thing that stands out is extending ResponseEntityExceptionHandler
. That shouldn't be necessary for global exception handling.
That said these questions are more suited for StackOverlow. I suggest however you prepare a sample to demonstrate the issues to improve the chance of getting a response.