Data Validation and Exception Handling [Java Spring Boot Mastery Series – Part 4]
🎯 Objective
Learn to validate incoming data using annotations and handle exceptions globally for consistent and informative error responses.
✅ Add Validation Dependency (if not already included)
In pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
This enables Java Bean Validation using annotations like @NotNull, @Size, etc.
🧾 Update Product Entity with Validation
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "Product name is required")
private String name;
@NotNull(message = "Price is required")
@Min(value = 0, message = "Price must be positive")
private Double price;
// Getters and Setters
}
🔍 Explanation
@NotBlank: Field must not be null or empty.@NotNull: Field must not be null.@Min: Value must be at least 0.
🔁 Update Controller to Validate Input
@PostMapping
public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
return new ResponseEntity<>(productService.save(product), HttpStatus.CREATED);
}
🔍 Explanation
@Valid: Triggers validation of the request body.- If validation fails, Spring throws a
MethodArgumentNotValidException.
❗ Global Exception Handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGenericException(Exception ex) {
return new ResponseEntity<>("Unexpected error: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
🔍 Explanation
@RestControllerAdvice: Handles exceptions across the whole application.- Catches validation errors, resource not found, and other generic exceptions.
- Returns user-friendly error messages.
🧪 Test with Invalid Input
POST /api/products
{
"name": "",
"price": -10
}
🔁 Response:
{
"name": "Product name is required",
"price": "Price must be positive"
}
✅ With this setup, you ensure clean, validated input and consistent error messages.
➡️ Next Up: Part 5 – Using DTOs and ModelMapper for Clean Architecture
