Card 05/ 07

GotchaDifficulty: Advanced1 min

Exception Handler Selection: The Most Specific Type Wins

A handler for Exception declared first still loses to a handler for the exact exception thrown.

When several @ExceptionHandler methods (methods Spring calls when an exception is thrown) could handle the same exception, Spring chooses the one whose declared type is closest to the exception's own type. The order in which the methods appear in the source file plays no part, which surprises anyone who expects the first match to win.

Declare a handler for Exception before a handler for RideNotFoundException, in the same class, and throw a RideNotFoundException:

java
// Generic handler declared BEFORE the specific one, on purpose.
@ExceptionHandler(Exception.class)
ResponseEntity<String> handleAll(Exception ex) {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("generic handler: " + ex.getMessage());
}

@ExceptionHandler(RideNotFoundException.class)
ResponseEntity<String> handleNotFound(RideNotFoundException ex) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND).body("specific handler: " + ex.getMessage());
}
text
STATUS -> 404
BODY -> specific handler: Ride not found with id: 100
run in a container: the Exception handler is declared first and still loses

The specific handler answered. RideNotFoundException matches its own handler exactly and is several steps from Exception in the class hierarchy, so its own handler is the closest match.

The mistake runs in both directions. Someone who expects declaration order to decide may reorder handlers to fix a problem that order never caused, or leave a catch-all Exception handler in place believing it shadows everything, when it only catches what nothing more specific handles.

So write a handler for each exception you want a particular response for, and keep one Exception handler as the fallback for everything else. Where they sit in the file does not matter.