| π Articles | π€ My Profile |
An exception is an unexpected event β‘ that occurs during program execution and disrupts the normal flow of instructions.
π Examples in Java:
NullPointerException β when trying to call a method on null.ArrayIndexOutOfBoundsException β accessing array index outside its limit.IOException β input/output problems (like file not found).SQLException β database-related error.β‘οΈ In short: exceptions are runtime errors caused by mistakes, invalid inputs, or system failures.
Exception Handling = the process of responding to exceptions in a controlled way β instead of letting the program crash π₯.
Benefits:
Java provides a robust mechanism with:
π try π§ͺ catch π― finally π throw π² throws π’
π» Example:
public class Example {
public static void main(String[] args) {
try {
int result = 10 / 0; // β‘ ArithmeticException
} catch (ArithmeticException ex) {
System.out.println("β Cannot divide by zero!");
} finally {
System.out.println("β
This block always executes.");
}
}
}
π€ Output:
β Cannot divide by zero!
β
This block always executes.
Here:
try β risky code.catch β handle exception.finally β always executes (cleanup code).throw β used to throw an exception.throws β declares exceptions in method signature.β So, in short:
In Spring Boot, exception handling = managing errors & unexpected conditions in a way that:
π By default, Spring Boot shows a whitelabel error page or JSON error response. In real-world apps, we customize it.
π‘ Letβs understand how Spring Boot Exception Handling works.

try-catch (Local Handling)The simplest way: wrap risky code inside try-catch in service/controller.
@GetMapping("/product/{id}")
public ResponseEntity<?> getProduct(@PathVariable Long id) {
try {
Product product = productService.findById(id);
return ResponseEntity.ok(product);
} catch (ProductNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("β Product not found");
}
}
β Simple but β clutters controllers β not recommended for big apps.
@ExceptionHandler (Controller Level)You can handle exceptions inside a controller using @ExceptionHandler.
@RestController
@RequestMapping("/products")
public class ProductController {
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id);
}
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<String> handleProductNotFound(ProductNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("β " + ex.getMessage());
}
}
β Keeps controller clean, but exception handling is limited to that controller.
@ControllerAdvice / @RestControllerAdvice (Global Handling π / β
Best Practice) This is the industry standard approach for global exception handling.
@ControllerAdvice β for MVC apps (views).@RestControllerAdvice β for REST APIs (returns JSON).@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ApiError> handleProductNotFound(ProductNotFoundException ex) {
ApiError error = new ApiError(HttpStatus.NOT_FOUND, ex.getMessage(), LocalDateTime.now());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class) // fallback
public ResponseEntity<ApiError> handleGeneral(Exception ex) {
ApiError error = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, "β οΈ Something went wrong!", LocalDateTime.now());
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
π DTO for response:
@Data
@AllArgsConstructor
public class ApiError {
private HttpStatus status;
private String message;
private LocalDateTime timestamp;
}
β Centralized error handling, reusable & clean π―
ResponseStatusExceptionYou can throw exceptions with HTTP status codes directly.
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "β Product not found"));
}
β Quick, useful for simple APIs. β Not very flexible for structured responses.
@ResponseStatus on Custom ExceptionsAnnotate custom exceptions with HTTP status.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ProductNotFoundException extends RuntimeException {
public ProductNotFoundException(String message) {
super(message);
}
}
When thrown, Spring automatically returns 404 Not Found.
β
Clean, no extra handler needed.
β Less control over response body.
ResponseEntityExceptionHandler (Spring Built-in) Spring provides ResponseEntityExceptionHandler for handling common exceptions like validation, MethodArgumentNotValidException, etc.
@RestControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
List<String> errors = ex.getBindingResult().getFieldErrors()
.stream().map(err -> err.getField() + ": " + err.getDefaultMessage())
.toList();
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, "Validation failed", errors);
return new ResponseEntity<>(apiError, HttpStatus.BAD_REQUEST);
}
}
β Best for handling Spring validation exceptions.
βοΈ Use @RestControllerAdvice with custom exceptions π― (clean, centralized, standard).
βοΈ Combine with ResponseEntityExceptionHandler for validation π
βοΈ Use @ResponseStatus for simple cases β‘
π₯οΈ Backend
π API Documentation
π’οΈ Database
π οΈ Build & Dependency Management
βοΈ Utilities
@Getter, @Setter, etc.)spring-boot-exception-handling
βββ π src/
β βββ π main/
β βββ π java/
β β βββ π com/sahu/springboot/basics/
β β βββ π config/
β β β βββ π OpenApiConfig.java
β β β βββ π OpenApiProperties.java
β β β
β β βββ π constant/
β β β βββ π ApiStatus.java
β β β
β β βββ π controller/
β β β βββ π rest/
β β β βββ π ProductRestController.java
β β β
β β βββ π dto/
β β β βββ π ApiResponse.java
β β β βββ π ProductRequest.java
β β β βββ π ProductResponse.java
β β β
β β βββ π exception/
β β β βββ π GlobalExceptionHandler.java
β β β βββ π ProductAlreadyExistException.java
β β β βββ π ProductNotFoundException.java
β β β
β β βββ π model/
β β β βββ π Product.java
β β β
β β βββ π repository/
β β β βββ π ProductRepository.java
β β β
β β βββ π service/
β β β βββ π impl/
β β β β βββ π ProductServiceImpl.java
β β β β
β β β βββ π ProductService.java
β β β
β β βββ π util/
β β β βββ π ProductUtil.java
β β β
β β βββ π SpringBootExceptionHandlingApplication.java
β β
β βββ π resources/
β βββ π application.yml
β
βββ π docker-compose.yml
βββ π pom.xml
You can find the complete code repository for this project on GitHub:
1οΈβ£ π³ Using Docker Compose (for MySQL container)
docker-compose up -d
β
This starts MySQL in a container (-d = detached mode).
π Verify with:
docker ps
π DB is now available at localhost:3307.
π Credentials (username, password, DB name) are in docker-compose.yml.
2οΈβ£ π» Run Directly in IntelliJ IDEA
SpringBootExceptionHandlingApplication.java3οΈβ£ β‘ Run with Maven Command (CLI)
βΆοΈ Run app:
mvn spring-boot:run
π Run app with debug mode:
mvn spring-boot:run -Dspring-boot.run.fork=false -Dmaven.surefire.debug
π¦ Build JAR and run:
mvn clean package -DskipTests
java -jar target/spring-boot-exception-handling-0.0.1-SNAPSHOT.jar
For a detailed running and demonstration of the application walkthrough,
watch the following YouTube video: