Reputation: 3610
I'm using Spring @ControllerAdvice to handle exceptions
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { DataIntegrityViolationException.class})
@ResponseBody
public ResponseEntity<String> unknownException(Exception ex, WebRequest req) {
return new ResponseEntity<>(ex.getCause().getMessage(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
The problem i'm experiencing is that when the exception occurs (when i send a request via swagger), i do not get an expected exception message, but :
{"error": "no response from server"}
Response Code : 0
Response Body : No Content
I can clearly see in debug mode that the method annotated by @ExceptionHandler
is called.
I've experimented with method return types, @ResponseBody
, @ResponseStatus
annotations and a few other thing that came to mind, but it seems that i only get some non-empty response when i return a ResponseEntity
without a body, e.g.
ResponseEntity.noContent().build()
or
ResponseEntity.ok().build()
In such cases i get correct http code and a few headers
Please advise on what i'm doing wrong
Thank you in advance
UPD
I carried on experimenting and this is the solution that worked for me. It is quite close to one of the answers - i will mark that one as accepted
In short, i just created my own dto class , populated the instance with the exception details i was interested in and returned it directly My code
@ExceptionHandler(value = { DataIntegrityViolationException.class})
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ExceptionDetailHolder unknownException(Exception ex, WebRequest req) {
final Throwable cause = ex.getCause();
return new ExceptionDetailHolder("Error interacting with the database server",
cause.getClass() + ":" + cause.getMessage(),
cause.getCause().getClass() + ":" + cause.getCause().getMessage()
);
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
private class ExceptionDetailHolder {
private String message;
private String exceptionMessage;
private String innerExceptionMessage;
}
Results (which also show the contents of ex.getMessage and ex.getCause().getMessage() as asked by commenters) :
{
"message": "Error interacting with the database server",
"exceptionMessage": "class org.hibernate.exception.ConstraintViolationException:could not execute statement",
"innerExceptionMessage": "class com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Column 'allow_copay_payments' cannot be null"
}
Upvotes: 5
Views: 6058
Reputation: 6818
My way of handling exception is like below, I find the specific exception and then create my own class object ValidationErrorDTO in this case, then populate required fields in that class (ValidationErrorDTO):
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ResponseEntity<ValidationErrorDTO> processValidationIllegalError(HttpMessageNotReadableException ex,
HandlerMethod handlerMethod, WebRequest webRequest) {
Throwable throwable = ex.getMostSpecificCause();
ValidationErrorDTO errorDTO = new ValidationErrorDTO();
if (throwable instanceof EnumValidationException) {
EnumValidationException exception = (EnumValidationException) ex.getMostSpecificCause();
errorDTO.setEnumName(exception.getEnumName());
errorDTO.setEnumValue(exception.getEnumValue());
errorDTO.setErrorMessage(exception.getEnumValue() + " is an invalid " + exception.getEnumName());
}
return new ResponseEntity<ValidationErrorDTO>(errorDTO, HttpStatus.BAD_REQUEST);
}
Upvotes: 3