How to write custom exceptions in spring boot?
Custom exceptions in Spring Boot allow you to define domain-specific error types, making your application's error handling more structured, readable, and easier to manage. This guide walks through the process of defining a custom exception, handling it globally, and using it within your application.
1. Define Your Custom Exception Class
First, create a simple Java class that extends either RuntimeException (for unchecked exceptions) or Exception (for checked exceptions). Unchecked exceptions are generally preferred in Spring Boot for most application-level errors as they don't force boilerplate try-catch blocks everywhere.
package com.example.myproject.exception;
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
2. Create a Global Exception Handler
To handle your custom exception gracefully across your entire application, create a global exception handler using @RestControllerAdvice (for REST APIs) or @ControllerAdvice (for MVC applications). This class centralizes exception handling logic.
package com.example.myproject.handler;
import com.example.myproject.exception.ResourceNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
// You can add more exception handlers here for other custom or built-in exceptions
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGeneralException(Exception ex) {
return new ResponseEntity<>("An unexpected error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
3. Use Your Custom Exception
Now you can throw your custom exception from any service layer, controller, or other component when a specific error condition is met.
package com.example.myproject.service;
import com.example.myproject.exception.ResourceNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public String getResourceById(Long id) {
if (id < 0) {
throw new IllegalArgumentException("ID cannot be negative");
}
if (id == 123L) {
return "Found resource with ID " + id;
} else {
throw new ResourceNotFoundException("Resource with ID " + id + " not found.");
}
}
}
4. Create a Controller to Test
Finally, create a simple REST controller to expose an endpoint that uses the service, allowing you to test your custom exception handling.
package com.example.myproject.controller;
import com.example.myproject.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/resources")
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/{id}")
public String getResource(@PathVariable Long id) {
return myService.getResourceById(id);
}
}
When you access /api/resources/123, you will get a 200 OK response. When you access /api/resources/456, the ResourceNotFoundException will be caught by GlobalExceptionHandler, and you'll receive a 404 Not Found response with the message "Resource with ID 456 not found.". If you access /api/resources/-1, you will get a 400 Bad Request with the message "ID cannot be negative" due to the IllegalArgumentException handler.