javaspring-bootexceptionhandler

Question about @ExceptionHandler(Exception.class)


There is an exception interceptor:

    @ControllerAdvice
    public class RestExceptionHandler extends ResponseEntityExceptionHandler {

        @ExceptionHandler
        public ResponseEntity<ApiExceptionDTO> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
            // return ResponseEntity<ApiExceptionDTO> with user friendly error message
        }

        // ... other @ExceptionHandler
        
        @ExceptionHandler(Exception.class)
        public ResponseEntity<ApiExceptionDTO> handleException(Exception ex) {
            // return ResponseEntity<ApiExceptionDTO>
        }

    }

I was tasked with returning a friendly error message to the user if he tries to delete an object from the database that violates the integrity constraint.

I caught the DataIntegrityViolationException exception and implemented the task.

I expected it to fail because of @ExceptionHandler(Exception.class), since it will intercept the error first.

My question is, why did it work the way I expected? Why @ExceptionHandler(Exception.class) didn't catch this exception first?

And in general, the question is what to do in the case when @ExceptionHandler(Exception.class) intercepts exceptions that should have hit another interceptor? Or is it possible only if somewhere in another interceptor there is a similar construction @ExceptionHandler(Exception.class) ?

SpringBoot version: 2.1.9.RELEASE


Solution

  • The @ControllerAdvice will look for the most appropriate @ExceptionHandler. To do this, it will use the class of the exception which is being thrown and it will check if any of the handlers are going to match it. If not, it will repeat the process with the parent of your class, then it will do it with the parent of its parent, and so on until it finds a handler.

    In this particular case, it will initially look for: @ExceptionHandler(DataIntegrityViolationException.class) then for @ExceptionHandler(NonTransientDataAccessException.class) then for @ExceptionHandler(DataAccessException.class) ... and, lastly, for @ExceptionHandler(Exception.class)