Spring Framework offers a powerful and flexible way to handle exceptions using annotations. These annotations make it easy to define centralized or localized error-handling logic, improving code clarity and maintainability.
This article explores the key Spring annotations used for exception handling, complete with examples and typical use cases.
🧩 Core Spring Exception Handling Annotations
✅ 1. @ExceptionHandler
Handles specific exceptions within a single controller class.
java
@Controller
public class MyController {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> handleMyException(MyException ex) {
return new ResponseEntity<>("Handled MyException", HttpStatus.BAD_REQUEST);
}
}
- Scope: Local to the controller
- Use: For simple, controller-specific exception responses
✅ 2. @ControllerAdvice
Used to apply exception handling globally across all controllers.
java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> handleMyException(MyException ex) {
return new ResponseEntity<>("Handled MyException globally", HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(AnotherException.class)
public ResponseEntity<String> handleAnotherException(AnotherException ex) {
return new ResponseEntity<>("Handled AnotherException", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
- Scope: Global
- Use: Centralized handling for all controllers
✅ 3. @ResponseStatus
Maps a custom exception to a specific HTTP status code, simplifying basic error mappings.
java
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
- Scope: Per exception class
- Use: For lightweight exception-to-status mapping without a handler method
✅ 4. @RestControllerAdvice
Specialized version of @ControllerAdvice
for REST APIs. Combines @ControllerAdvice
with @ResponseBody
so responses are automatically serialized (e.g., JSON).
java
@RestControllerAdvice
public class RestGlobalExceptionHandler {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> handleMyException(MyException ex) {
return new ResponseEntity<>("Handled MyException in REST", HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(AnotherException.class)
public ResponseEntity<String> handleAnotherException(AnotherException ex) {
return new ResponseEntity<>("Handled AnotherException in REST", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
- Scope: Global, for REST controllers
- Use: Ensures exceptions return JSON or XML responses automatically
📌 Summary of Annotations
AnnotationScopeUse Case@ExceptionHandler
Local (Controller)Handle exceptions within a controller@ControllerAdvice
GlobalReusable exception logic across app@ResponseStatus
Exception classSet status without writing handler@RestControllerAdvice
Global (REST)JSON/XML error response for REST APIs
✅ Best Practices
- Use
@ControllerAdvice
or @RestControllerAdvice
for global exception handling. - Use
@ResponseStatus
for static mappings. - Always log exceptions internally for debugging.
- Return structured error responses (e.g., JSON with
message
, timestamp
, path
).
These annotations make exception handling in Spring both clean and powerful, helping you build robust web and RESTful applications with clear error semantics.