Global Exception Handling with @ControllerAdvice
Centralize exception handling across all controllers with @ExceptionHandler and @ControllerAdvice.
Global Exception Handling with @ControllerAdvice is a free Java Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Problem Without Global Handling
Without global exception handling, every controller method needs try-catch blocks, error response building is duplicated, and exception details leak to clients.
@ControllerAdvice and @RestControllerAdvice
@ControllerAdvice defines a global exception handler class. @RestControllerAdvice adds @ResponseBody so all handler methods return JSON automatically.
@RestControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler methods go here
}@ExceptionHandler Methods
Annotate a method with @ExceptionHandler(ExceptionType.class). Spring routes exceptions of that type (and subclasses) to the method. Return a ResponseEntity with the appropriate status.
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}Handling Multiple Exception Types
List multiple exception types in one handler or use a common base class. Spring picks the most specific handler available.
@ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})
public ResponseEntity<ErrorResponse> handleBadRequest(RuntimeException ex) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("BAD_REQUEST", ex.getMessage()));
}Handling Validation Errors
Catch MethodArgumentNotValidException to extract field-level errors from @Valid validated request bodies.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> fieldErrors = new LinkedHashMap<>();
ex.getBindingResult().getFieldErrors().forEach(e ->
fieldErrors.put(e.getField(), e.getDefaultMessage()));
return ResponseEntity.badRequest()
.body(Map.of("errors", fieldErrors, "status", 400));
}Handling Constraint Violations
ConstraintViolationException is thrown when validating method parameters with @Validated at the service layer. Handle it separately from MVC validation errors.
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Map<String, String>> handleConstraint(ConstraintViolationException ex) {
Map<String, String> errors = new LinkedHashMap<>();
ex.getConstraintViolations().forEach(v ->
errors.put(v.getPropertyPath().toString(), v.getMessage()));
return ResponseEntity.badRequest().body(errors);
}Access to HttpServletRequest
Add HttpServletRequest as a parameter to get request details (URL, method, headers) for logging or including in the error response.
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
log.error("Unhandled error on {} {}", req.getMethod(), req.getRequestURI(), ex);
return ResponseEntity.internalServerError()
.body(new ErrorResponse("INTERNAL_ERROR", "Unexpected error"));
}@ResponseStatus on Exception Classes
Annotate custom exception classes with @ResponseStatus to automatically set the HTTP status without a handler method — simpler for straightforward cases.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String msg) { super(msg); }
}Scoping @ControllerAdvice
Restrict the advice to specific packages, annotations, or base classes using attributes on @ControllerAdvice.
@RestControllerAdvice(basePackages = "com.example.api")
public class ApiExceptionHandler { ... }
@RestControllerAdvice(assignableTypes = {UserController.class, OrderController.class})
public class SpecificHandler { ... }Logging in Exception Handlers
Log exceptions at the appropriate level: user errors (4xx) at WARN, unexpected errors (5xx) at ERROR with the full stack trace.
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
if (ex instanceof BusinessException) log.warn("Business error: {}", ex.getMessage());
else log.error("Unexpected error on {}", req.getRequestURI(), ex);
return ...
}Exception Handler Priority
Spring picks the most specific handler. If ResourceNotFoundException extends RuntimeException, a handler for ResourceNotFoundException takes priority over one for RuntimeException.
Quick Check
What annotation marks a method to handle a specific exception type globally?
Recap
Use @RestControllerAdvice + @ExceptionHandler to centralize error handling. Return ResponseEntity with consistent error structure. Handle validation (MethodArgumentNotValidException) and constraints (ConstraintViolationException) separately. Log 4xx as WARN, 5xx as ERROR.
Frequently asked questions
Is the “Global Exception Handling with @ControllerAdvice” lesson free?
Yes — the full text of “Global Exception Handling with @ControllerAdvice” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Global Exception Handling with @ControllerAdvice”?
Centralize exception handling across all controllers with @ExceptionHandler and @ControllerAdvice. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Global Exception Handling with @ControllerAdvice” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Bean Validation: @NotNull, @Size, @Pattern
- Custom Constraint Annotations
- Global Exception Handling with @ControllerAdvice
- RFC 7807 Problem Details and Consistent Error Responses