Validation with @Valid
Add Bean Validation annotations like @NotNull and @Size to your entity classes, and enforce them automatically in controllers with @Valid.
Introduction
Right now, your CRUD API accepts absolutely anything a client sends: an empty name, a malformed email, a negative age. Manually checking every field at the top of every controller method quickly becomes repetitive and error-prone. Bean Validation is a Java standard that lets you declare constraints directly on your model classes, and Spring Boot enforces them automatically the moment you add one annotation to a controller parameter: @Valid.
- How to add the Bean Validation starter to your project.
- The most commonly used validation annotations.
- How @Valid triggers validation automatically before your method body runs.
- What Spring Boot's default response looks like when validation fails.
Adding the Validation Starter
Bean Validation is not included in spring-boot-starter-web by default in recent Spring Boot versions, so add spring-boot-starter-validation explicitly.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId></dependency>Common Validation Annotations
These annotations come from the jakarta.validation.constraints package and are placed directly on entity or request model fields.
| Annotation | Rule |
|---|---|
| @NotNull | Value must not be null |
| @NotBlank | String must not be null and must contain at least one non-whitespace character |
| @NotEmpty | Collection or String must not be null or empty |
| @Size(min, max) | String or collection length must fall within the given range |
| String must be a syntactically valid email address | |
| @Min / @Max | Numeric value must be at least / at most the given value |
| @Positive | Numeric value must be greater than zero |
import jakarta.persistence.Entity;import jakarta.persistence.GeneratedValue;import jakarta.persistence.GenerationType;import jakarta.persistence.Id;import jakarta.validation.constraints.Email;import jakarta.validation.constraints.NotBlank;import jakarta.validation.constraints.Size;
@Entitypublic class Student {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@NotBlank(message = "Name is required") @Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters") private String name;
@NotBlank(message = "Email is required") @Email(message = "Email must be a valid address") private String email;
// getters and setters public Long getId() { return id; } public void setId(Long id) { this.id = id; }
public String getName() { return name; } public void setName(String name) { this.name = name; }
public String getEmail() { return email; } public void setEmail(String email) { this.email = email; }}Triggering Validation with @Valid
Adding these annotations to the class does nothing by itself — Spring only runs the checks when you mark the @RequestBody parameter with @Valid.
@PostMappingpublic ResponseEntity<Student> createStudent(@Valid @RequestBody Student student) { Student saved = studentRepository.save(student); return ResponseEntity.status(HttpStatus.CREATED).body(saved);}@Valid must come before @RequestBody, or immediately alongside it — Spring reads it as a signal to run validation on that parameter's value before the method body executes at all. If validation fails, your method body never runs.
What Happens on Failure
When validation fails, Spring Boot throws a MethodArgumentNotValidException, which its default exception handling converts into a 400 Bad Request response describing exactly which fields failed and why.
Click Run to see what this code prints.
The exact shape of this error response is Spring Boot's default, and it isn't very client-friendly on its own. The next lesson covers @ControllerAdvice and @ExceptionHandler, which let you catch MethodArgumentNotValidException and shape the response exactly how you want.
Common Mistakes
- Adding validation annotations to a class but forgetting @Valid on the controller parameter — without it, nothing is ever checked.
- Confusing @NotNull with @NotBlank on a String field — @NotNull allows an empty string "" to pass, which is rarely what you want for required text fields.
- Forgetting to add spring-boot-starter-validation, causing @Valid to be silently ignored in newer Spring Boot versions.
- Putting validation only on the entity and not on separate request DTOs, once your project grows to use DTOs instead of exposing entities directly.
Best Practices
- Always pair validation annotations on a model class with @Valid on every controller parameter that accepts one.
- Use @NotBlank rather than @NotNull for required String fields, since it also rejects empty and whitespace-only values.
- Write clear, specific messages on each constraint annotation — they surface directly in error responses.
- Handle validation failures centrally with @ControllerAdvice rather than checking BindingResult manually in every method.
Frequently Asked Questions
Not by default in the same way. For method-level validation of simple parameters, you annotate the controller class itself with @Validated (from org.springframework.validation.annotation.Validated) and add constraints directly on the parameters.
@Valid is the standard Bean Validation annotation and is what you use on @RequestBody parameters. @Validated is a Spring-specific annotation that additionally supports validation groups and enables method-level parameter validation on a class.
Yes, using @Constraint together with a class implementing ConstraintValidator. This is useful for rules that don't fit the built-in annotations, like checking a username is unique.
Before. @Valid runs as part of Spring's request-handling pipeline, prior to your controller method body executing, so invalid data never reaches your service or repository layer.
Key Takeaways
- Bean Validation annotations like @NotBlank, @Size, and @Email are declared directly on model fields.
- @Valid on a @RequestBody parameter triggers those checks automatically before the controller method runs.
- Failed validation throws MethodArgumentNotValidException, which Spring Boot converts into a 400 Bad Request by default.
- @Validated extends validation support to path variables and request parameters at the class level.
Summary
Your API now rejects invalid data automatically, before it ever reaches your database. Next, you'll learn how to take full control of error responses — including validation failures — using @ControllerAdvice and @ExceptionHandler.