Spring Boot Tutorial
Spring Boot - Software Setup and Configuration (STS/Eclipse/IntelliJ)
Prerequisite (Spring Core Concepts)
Spring Boot Core
Spring Boot with REST API
Spring Boot with Database and Data JPA
Spring Boot with Kafka
Spring Boot with AOP
In Spring Boot applications, handling exceptions properly is crucial to ensure a good user experience and maintainability of the code. Spring Boot provides several ways to handle exceptions effectively:
@ControllerAdvice and @ExceptionHandler:
@ControllerAdvice
: It's a centralized way of handling exceptions for your controllers. You can define a class with this annotation, and within that class, you can define methods annotated with @ExceptionHandler
.@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = {SomeSpecificException.class}) public ResponseEntity<Object> handleSomeSpecificException(SomeSpecificException ex) { // logic to handle the exception return new ResponseEntity<>("Error message or object", HttpStatus.BAD_REQUEST); } }
@ExceptionHandler
: You can use this inside controllers to handle exceptions specific to that controller.@RestController public class MyController { @ExceptionHandler(value = {AnotherException.class}) public ResponseEntity<Object> handleAnotherException(AnotherException ex) { // logic to handle the exception return new ResponseEntity<>("Error message for this controller", HttpStatus.BAD_REQUEST); } // ... your controller methods ... }
Custom Error Attributes:
You can customize the error attributes returned during an exception by implementing the ErrorAttributes
interface.
Custom ErrorController:
By default, Spring Boot provides a /error
mapping through its BasicErrorController
. If you wish to customize this behavior, you can implement the ErrorController
interface.
ResponseStatusException:
Spring 5 introduced ResponseStatusException
, which can be thrown directly from controllers or service methods. It combines an HTTP status code and a reason string (or another exception).
@GetMapping("/someEndpoint") public SomeObject getSomeObject() { if (someCondition) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Object not found"); } // ... other logic ... }
Error Responses:
When designing your error responses, it's a good practice to create a standardized error response structure, so clients of your API always receive errors in a consistent format.
public class ApiError { private LocalDateTime timestamp; private int status; private String error; private String message; private String path; // getters, setters, constructors ... }
Using @Valid
for Validations:
For request body validations (for example, when you bind JSON to an object), you can use @Valid
with your request model. If validation fails, a MethodArgumentNotValidException
is thrown.
@PostMapping("/create") public ResponseEntity<Object> createObject(@Valid @RequestBody SomeRequestModel request) { // ... method logic ... }
You can then handle MethodArgumentNotValidException
in your @ControllerAdvice
class to return a meaningful error response.
Logging:
Ensure you log exceptions properly using a logging framework like SLF4J or Logback. This ensures that while the user gets a friendly and standardized error message, developers can have detailed logs to debug issues.
Exception handling in Spring Boot is powerful and flexible, allowing you to cater to a variety of requirements while ensuring that the application gracefully handles unexpected situations.
Global exception handling in Spring Boot:
@ControllerAdvice
and @ExceptionHandler
.Example (GlobalExceptionHandler
class):
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("An unexpected error occurred"); } }
Using @ExceptionHandler
in Spring Boot:
@ExceptionHandler
to handle specific exceptions.Example (UserController
class):
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<String> handleUserNotFoundException(UserNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body("User not found: " + ex.getMessage()); } }
Custom exception handling in Spring Boot:
RuntimeException
.Example (UserNotFoundException
class):
public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { super(message); } }
Exception translation in Spring Boot:
@RepositoryRestResource(exported = false)
to hide repository methods.Example (CustomDataAccessExceptionTranslator
class):
import org.springframework.dao.DataAccessException; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; public class CustomDataAccessExceptionTranslator extends PersistenceExceptionTranslationPostProcessor { @Override protected DataAccessException customTranslate(String task, String sql, DataAccessException ex) { return new CustomDataAccessException("Custom translation message", ex); } }
Logging exceptions in Spring Boot applications:
Example (MyService
class with SLF4J):
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyService { private static final Logger logger = LoggerFactory.getLogger(MyService.class); public void process() { try { // Business logic that may throw an exception } catch (Exception e) { logger.error("An error occurred during processing", e); } } }
Error response formats and HTTP status codes in Spring Boot:
Example (ErrorResponse
class):
public class ErrorResponse { private int status; private String message; // Constructors, getters, and setters }
Handling validation errors in Spring Boot:
@Valid
annotation for request validation.BindingResult
in the controller.Example (UserController
class):
import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; @RestController @Validated public class UserController { @PostMapping("/users") public ResponseEntity<String> createUser(@RequestBody @Valid User user, BindingResult result) { if (result.hasErrors()) { // Handle validation errors } // Continue with the normal flow } }
Exception handling with ResponseEntity
in Spring Boot:
ResponseEntity
to provide flexibility in the response.Example (UserController
class):
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @RestController public class UserController { @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<String> handleUserNotFoundException(UserNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body("User not found: " + ex.getMessage()); } }