Validation is crucial in Spring Boot applications. Here’s a complete guide to using @Valid and @Validated.
Basic Validation
Dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Bean Validation
public class CreateUserRequest {
@NotBlank(message = "Name is required")
private String name;
@Email(message = "Invalid email format")
@NotBlank
private String email;
@Min(value = 18, message = "Age must be at least 18")
@Max(value = 120, message = "Age must be at most 120")
private Integer age;
}
@Valid vs @Validated
@Valid
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) {
// Validates request object
}
@Validated
@RestController
@Validated
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable @Min(1) Long id) {
// Validates path variable
}
}
Custom Validators
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface PhoneNumber {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.matches("^\\+?[1-9]\\d{1,14}$");
}
}
Validation Groups
public interface CreateGroup {}
public interface UpdateGroup {}
public class UserRequest {
@NotNull(groups = UpdateGroup.class)
private Long id;
@NotBlank(groups = {CreateGroup.class, UpdateGroup.class})
private String name;
}
@PostMapping("/users")
public ResponseEntity<User> create(@Validated(CreateGroup.class) @RequestBody UserRequest request) {
// Only validates CreateGroup fields
}
Error Handling
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.badRequest()
.body(new ErrorResponse("Validation failed", errors));
}
}
Best Practices
- Validate at controller level
- Use appropriate annotations
- Create custom validators
- Handle validation errors
- Use validation groups
Conclusion
Spring Boot validation provides:
- Declarative validation
- Custom validators
- Error handling
- Type safety
Validate your data properly! ✅