Component Inspector
Click on any component in the diagram to explore its role in the global exception handling architecture.
Simulation Legend
Spring Boot: Global Exception Handling
Building robust REST APIs isn't just about handling the happy path; it's about how gracefully your application fails. Unhandled exceptions result in generic 500 server errors with messy stack traces exposing internal architecture. Spring Boot provides a powerful, elegant way to handle errors globally.
Centralization
Don't clutter your `@RestController` methods with `try/catch` blocks. Separate business logic from error handling logic to adhere to the Single Responsibility Principle.
Standardization
Clients expect a consistent error format. Spring 3.0 introduced native support for RFC 7807 Problem Details, creating a universal JSON structure for HTTP API errors.
Core Components
1. @RestControllerAdvice
This annotation is a specialized `@Component` that allows you to consolidate your multiple, scattered `@ExceptionHandler`s into a single, global error handling component.
@RestControllerAdvice
public class GlobalExceptionHandler {
// Exception handlers go here
}
2. Handling Custom Business Exceptions (e.g., 404 Not Found)
When your service layer throws a `UserNotFoundException`, the dispatcher routes it here. We map it to a 404 Not Found status and return a `ProblemDetail`.
@ExceptionHandler(UserNotFoundException.class)
public ProblemDetail handleUserNotFoundException(UserNotFoundException ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND,
ex.getMessage()
);
problemDetail.setTitle("User Not Found");
problemDetail.setType(URI.create("https://api.example.com/errors/not-found"));
problemDetail.setProperty("timestamp", Instant.now());
return problemDetail;
}
3. Handling Validation Exceptions (e.g., 400 Bad Request)
When a client sends bad data that fails `@Valid` checks, Spring throws a `MethodArgumentNotValidException`. We can catch this, extract the specific field errors, and append them to our `ProblemDetail`.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ProblemDetail handleValidationErrors(MethodArgumentNotValidException ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
HttpStatus.BAD_REQUEST,
"Request validation failed"
);
// Extract field-level errors
List<Map<String, String>> fieldErrors = ex.getBindingResult().getFieldErrors()
.stream()
.map(err -> Map.of(
"field", err.getField(),
"message", err.getDefaultMessage()
)).toList();
// Add custom property to RFC 7807 spec
problemDetail.setProperty("invalid_params", fieldErrors);
return problemDetail;
}
The RFC 7807 Output
The resulting JSON response looks exactly like the standardized spec demands:
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Request validation failed",
"instance": "/api/users",
"invalid_params": [
{
"field": "email",
"message": "must be a well-formed email address"
}
]
}