In Spring Boot, exception handling is usually done with the @ControllerAdvice
and @ExceptionHandler
annotations. This helps you catch exceptions globally and return proper responses (e.g., JSON error messages) instead of exposing stack traces.
Here’s a simple example:
1. Create a Custom Exception
package com.example.demo.exception;
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
2. Service/Controller that throws Exception
package com.example.demo.controller;
import com.example.demo.exception.ResourceNotFoundException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@GetMapping("/users/{id}")
public String getUser(@PathVariable int id) {
if (id != 1) {
throw new ResourceNotFoundException("User not found with id " + id);
}
return "User found with id " + id;
}
}
3. Global Exception Handler
package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
// Handle specific exception
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> handleResourceNotFound(ResourceNotFoundException ex) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.NOT_FOUND.value());
body.put("error", "Not Found");
body.put("message", ex.getMessage());
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}
// Handle generic exception
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleGeneralException(Exception ex) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
body.put("error", "Internal Server Error");
body.put("message", ex.getMessage());
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
4. Example API Call
- Request:
GET http://localhost:8080/users/2
- Response:
{ "timestamp": "2025-08-21T10:15:30", "status": 404, "error": "Not Found", "message": "User not found with id 2" }
✅ With this setup:
- Specific exceptions (like
ResourceNotFoundException
) return meaningful JSON error messages. - Any other unhandled exceptions are caught by the generic
ExceptionHandler
.