Spring Boot – Exception Handling (Deep Notes)

1. Core Classes in Spring Exception Handling
From the class diagram on page 1:
HandlerExceptionResolver (interface)
|
HandlerExceptionResolverComposite
|
AbstractHandlerExceptionResolver
|
---------------------------------------------------
| | |
ExceptionHandlerExceptionResolver ResponseStatusExceptionResolver DefaultHandlerExceptionResolver
What each does:
| Resolver | Responsibility |
|---|---|
| ExceptionHandlerExceptionResolver | Handles @ExceptionHandler & @ControllerAdvice |
| ResponseStatusExceptionResolver | Handles exceptions annotated with @ResponseStatus |
| DefaultHandlerExceptionResolver | Handles Spring framework exceptions like 404, 405 |
2. Exception Flow (Page 1 Diagram)
When an exception occurs:
DispatcherServletcatches it- Passes it to
HandlerExceptionResolverComposite - It tries resolvers in order (left → right):
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
- If none can handle → goes to DefaultErrorAttributes
- Builds final error response
3. Example: Unhandled Exception
From page 1:
@GetMapping("/get-user")
public String getUser() {
throw new NullPointerException("throwing null pointer exception for testing");
}
Output (page 2):
{
"timestamp": "...",
"status": 500,
"error": "Internal Server Error",
"path": "/api/get-user"
}
Because:
- No resolver handled it
DefaultErrorAttributesfilled default values
4. Why Custom Exception also returns 500? (Page 2)
Even when you throw:
throw new CustomException(HttpStatus.BAD_REQUEST, "UserID is missing");
It still returns 500 because:
You are NOT returning ResponseEntity
So Spring’s resolvers decide the response
5. DefaultErrorAttributes (Page 3)
It builds default response fields:
- timestamp
- status
- error
- path
- message (if allowed)
And finally:
return new ResponseEntity<>(body, status);
6. ExceptionHandlerExceptionResolver (Page 4)
Handles:
@ExceptionHandler@ControllerAdvice
Controller Level Example
@ExceptionHandler(CustomException.class)
public ResponseEntity<String> handle(CustomException ex) {
return ResponseEntity.status(ex.getStatus()).body(ex.getMessage());
}
Now response is controlled by you.
7. Multiple @ExceptionHandler (Page 4–5)
You can handle multiple exceptions:
@ExceptionHandler({CustomException.class, IllegalArgumentException.class})
public ResponseEntity<String> handleAll(Exception ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
}
8. Global Exception Handling (Page 5)
Problem with controller-level:
Code duplication
Solution:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<String> handle(CustomException ex) {
return new ResponseEntity<>(ex.getMessage(), ex.getStatus());
}
}
9. Priority: Controller vs Global (Page 6)
If both exist:
Controller-level handler gets priority
10. If Two Handlers Can Handle Same Exception
Rule (page 6):
Spring chooses the most specific match first
Then parent class
11. ResponseStatusExceptionResolver (Page 6–7)
Handles exceptions annotated with:
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class CustomException extends RuntimeException {}
Then:
throw new CustomException("UserID missing");
It will return 400 without @ExceptionHandler.
12. Conflict: @ExceptionHandler + @ResponseStatus (Page 7)
If both exist:
- Spring uses ExceptionHandlerExceptionResolver first
- @ResponseStatus is ignored
👉 Recommendation: Do not mix both
13. DefaultHandlerExceptionResolver (Page 8)
Handles:
- MethodNotAllowed (405)
- NoResourceFound (404)
- MissingPathVariable
- TypeMismatch, etc.
EXTRA REAL-WORLD POINTS
- Always return ResponseEntity in handlers
- Use ErrorResponse DTO
- Log full stack trace, return safe message
- Use @ControllerAdvice in microservices
- Never expose internal exception messages
INTERVIEW QUESTIONS & ANSWERS
Q1. What is HandlerExceptionResolver?
Ans: Interface used by Spring to resolve exceptions to HTTP responses.
Q2. Resolver execution order?
Ans:
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
Q3. Why custom exception returns 500?
Ans: Because no ResponseEntity is created, so DefaultErrorAttributes builds response.
Q4. Which has higher priority: controller or global?
Ans: Controller-level @ExceptionHandler.
Q5. When to use @ResponseStatus?
Ans: For simple static status mapping without ResponseEntity.
Q6. Can we use both @ResponseStatus and @ExceptionHandler?
Ans: Not recommended – leads to conflict.
Q7. What does DefaultHandlerExceptionResolver handle?
Ans: Spring framework exceptions like 404, 405.