Exception Handling with @ControllerAdvice
@ControllerAdvice centralizes error handling across every controller. With @ExceptionHandler methods returning ResponseEntity error bodies — or a quick ResponseStatusException — your API speaks in clean, consistent status codes.
Learn Exception Handling with @ControllerAdvice in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise…
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You should understand Java exceptions and how Spring REST controllers return responses. The validation lesson pairs well with this one.
💡 Analogy: Without central handling, every office (controller) keeps its own first-aid kit and gives different answers when something goes wrong. @ControllerAdvice is a single help desk for the whole building: whenever any office raises a problem, it routes to the right specialist ( @ExceptionHandler ) who responds with a consistent, well-formatted answer — the right status code and a tidy error body — every time.
Controllers stay focused on the happy path; the advice handles the unhappy ones.
Annotate a class with @RestControllerAdvice and add an @ExceptionHandler method per error type. Each returns a ResponseEntity with the right status and a structured body. A catch-all prevents raw stack traces from leaking.
Throw a custom domain exception (handled by the advice) for reusable, meaningful errors, or a ResponseStatusException inline for quick one-offs. Both end up as the correct HTTP status.
Spring picks the handler whose exception type best matches what was thrown, falling back to a catch-all. Here is that "match by type" dispatch in plain Java you can run.
Answer: the more specific ResourceNotFoundException handler; Exception is the fallback.
Answer: @ResponseBody — return values are serialized as the JSON response body.
🎯 YOUR TURN — Map a 409 Conflict
Add an @ExceptionHandler for a DuplicateEmailException that returns 409 Conflict .
🧩 MINI-CHALLENGE — One handler, two exceptions
Handle both IllegalArgumentException and IllegalStateException with a single handler returning 400.
You can now centralize error handling with @ControllerAdvice , map exception types with @ExceptionHandler , return precise ResponseEntity error bodies, throw ResponseStatusException inline, and pick correct HTTP status codes.
Next up: DTOs & Mapping — why you should not expose entities, and how to convert between them cleanly.
Practice quiz
What does a class annotated with @ControllerAdvice provide?
- Cross-cutting exception handling shared across controllers
- A new controller endpoint
- A database connection
- A scheduled task
Answer: Cross-cutting exception handling shared across controllers. @ControllerAdvice centralizes exception handling (and other advice) across all controllers in one place.
What does @ExceptionHandler(SomeException.class) do?
- Throws the exception
- Maps that exception type to a handler method
- Logs only
- Disables the exception
Answer: Maps that exception type to a handler method. @ExceptionHandler binds a method to handle the listed exception type(s) when thrown by a controller.
What is the benefit of returning ResponseEntity from a handler?
- It hides the body
- It is required by Java
- It caches the response
- You control both the HTTP status and the response body
Answer: You control both the HTTP status and the response body. ResponseEntity lets you set the status code, headers, and body explicitly for the error response.
What does throwing a ResponseStatusException(HttpStatus.NOT_FOUND) result in?
- A 200 response
- A 404 response with that status
- A compile error
- A redirect
Answer: A 404 response with that status. ResponseStatusException maps directly to the given HTTP status, here 404 Not Found.
Which combination makes a @RestController-style advice that returns JSON bodies?
- @Controller only
- @ControllerAdvice + @ResponseBody, or @RestControllerAdvice
- @Service
- @Component only
Answer: @ControllerAdvice + @ResponseBody, or @RestControllerAdvice. @RestControllerAdvice = @ControllerAdvice + @ResponseBody, so handler return values become JSON bodies.
If two @ExceptionHandler methods could match, which is chosen?
- A random one
- The one for the most specific exception type
- The first declared
- Both run
Answer: The one for the most specific exception type. Spring picks the handler whose declared exception type is the most specific match for the thrown exception.
What status is conventional for a failed bean validation on a request body?
- 201 Created
- 403 Forbidden
- 400 Bad Request
- 500 Internal Server Error
Answer: 400 Bad Request. Invalid input is a client error, conventionally returned as 400 Bad Request.
Why centralize error handling in @ControllerAdvice instead of try/catch everywhere?
- It runs faster
- It avoids duplicated handling and gives consistent error responses
- It removes exceptions
- It is mandatory
Answer: It avoids duplicated handling and gives consistent error responses. Centralizing avoids repeating try/catch in every controller and yields uniform, consistent error responses.
What HTTP status best fits an unexpected server-side failure?
- 400
- 404
- 500 Internal Server Error
- 204
Answer: 500 Internal Server Error. Unhandled or unexpected server errors map to 500 Internal Server Error.
Can a single @ExceptionHandler handle multiple exception types?
- No, only one
- Only via inheritance
- Only with reflection
- Yes, by listing several classes in the annotation
Answer: Yes, by listing several classes in the annotation. You can pass an array of exception classes to @ExceptionHandler to handle several types with one method.