Robert Strauch
Robert Strauch

Reputation: 12896

Better approach than defining an @ExceptionHandler for Exception.class to handle errors?

In my Spring Boot project I defined some @ExceptionHandler classes in a @ControllerAdvice to handle specific exceptions. These build an application-specific JSON reponse instead of the default provided by Spring Boot. So far this works fine for e.g. the MethodArgumentNotValidException which is thrown in case the request validation fails.

@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseEntity<ApplicationResponse> handleValidationException(MethodArgumentNotValidException ex) {
    Map<String, String> errors = new HashMap<>();
    ex.getBindingResult().getAllErrors().forEach((error) -> {
        String fieldName = ((FieldError) error).getField();
        String errorMessage = error.getDefaultMessage();
        errors.put(fieldName, errorMessage);
    });
    log.error("Validation failed: {}", errors);
    return buildErrorResponse(ApplicationError.REQUEST_BODY_VALIDATION_FAILED, errors.toString(), HttpStatus.BAD_REQUEST);
}

This approach seems reasonable to me for all exceptions I'm aware of. But what happens if an exception is thrown for which no @ExceptionHandler exists? Then Spring Boot's default will kick in resulting in a JSON response which looks different from my custom one.

My first idea was to add an @ExceptionHandler for the Exception class like this:

@ExceptionHandler(value = {Exception.class})
public ResponseEntity<ApplicationResponse> handleValidationException(Exception ex) {
    log.error("An unhandled error occurred: {}", ex.getMessage());
    return buildErrorResponse(ApplicationError.GENERIC_ERROR, HttpStatus.INTERNAL_SERVER_ERROR);
}

While this seems to be working I wonder if this approach could have some major drawbacks I'm not aware of. How would you response with a custom JSON structure for any error that might occur?

Upvotes: 1

Views: 1376

Answers (1)

user731136
user731136

Reputation:

Spring has several ways to deal with an exception handler as you can see here. Use @ControllerAdvice with several @ExceptionHandler has the following advantages:

  • Centralized class to deal with not catched exceptions.
  • Customization about how you want to manage specific ones.

Regarding to include a @ExceptionHandler(value = {Exception.class}) to manage exceptions without an specific handler, a better option is create the next one: @ExceptionHandler(Throwable.class), in that way you will be able to manage all potential problems in your application.

About return a Json when in your application an error happens, you can configure it in the response itself. For example:

private ResponseEntity<ErrorResponseDto> buildErrorResponse(RestApiErrorCode errorCode, List<String> errorMessages, HttpStatus httpStatus) {
  HttpHeaders headers = new HttpHeaders();
  headers.setContentType(APPLICATION_JSON);

  ErrorResponseDto error = new ErrorResponseDto(errorCode, errorMessages);
  return new ResponseEntity<>(error, headers, httpStatus);
}

You can see the rest of the code here

Upvotes: 1

Related Questions