Spring Boot: From Basics to Production · Validation and Error Handling

Bean Validation

Validate requests with Jakarta Bean Validation annotations.

Add the validation starter and annotate DTO fields with Jakarta Bean Validation constraints (@NotBlank, @Email, @Size, @Positive, @Past). @Valid on a @RequestBody triggers validation; failures throw MethodArgumentNotValidException, returned as 400. Use @Valid on nested objects and lists, and validation groups when create and update need different rules.

public record RegisterRequest(
        @NotBlank @Email String email,
        @NotBlank @Size(min = 12, max = 128) String password,
        @NotNull @Past LocalDate birthDate,
        @Valid @NotNull AddressRequest address,
        @Size(max = 5) List<@NotBlank String> interests) {}

public record AddressRequest(@NotBlank String street, @NotBlank @Pattern(regexp = "[A-Z]{2}") String country) {}

@PostMapping("/api/v1/users")
ResponseEntity<UserResponse> register(@Valid @RequestBody RegisterRequest request) { /* ... */ }

Common pitfalls

  • Forgetting @Valid — annotations alone do nothing.
  • Missing @Valid on nested objects.
  • Duplicating business rules (like uniqueness) as annotations that need database access.

Key points

  • Constraints on DTO fields
  • @Valid triggers validation (also nested)
  • Business rules in services

Further reading: Spring: Bean Validation

Practice questions

Why might @NotBlank on a nested DTO field not be enforced?

Answer

Nested objects are only validated if the field referencing them is annotated with @Valid.

Where should a 'username must be unique' rule live?

Answer

In the service layer (backed by a database unique constraint), since it requires I/O and must be enforced atomically.

Open in the app to mark lessons complete, take notes and track your progress.