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@ExceptionHandlerLocal (Controller)Handle exceptions within a controller@ControllerAdviceGlobalReusable exception logic across app@ResponseStatusException classSet status without writing handler@RestControllerAdviceGlobal (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.