Backend Development 16 min read

Mastering Spring Boot 3 Validation: From Annotations to Global Error Handling

This article provides a comprehensive guide to data validation in Spring Boot 3, covering Bean Validation annotations, controller and service‑layer checks, JPA entity validation, custom constraints, validation groups, programmatic validation, and internationalized error messages with practical code examples and tests.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Boot 3 Validation: From Annotations to Global Error Handling

1. Introduction

Ensuring that incoming data conforms to expected formats and rules is essential for robust and secure Spring Boot applications. Spring Boot leverages the Bean Validation API (JSR‑380) and Hibernate Validator to simplify this process.

2. Practical Cases

2.1 Basic Annotations

Common validation annotations include @NotNull , @Size , @Min , @Max , @NotEmpty , @NotBlank , and @Pattern . Add the starter dependency to enable Hibernate Validator:

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  &lt;artifactId&gt;spring-boot-starter-validation&lt;/artifactId&gt;
&lt;/dependency&gt;</code>

2.2 Controller Parameter Validation

Three kinds of parameters can be validated:

Request Body : use @Valid or @Validated on the method argument.

Path Variables : annotate the variable with validation constraints (e.g., @Min(5) ).

Query Parameters : apply constraints directly on the method parameter.

Example of a validated request body:

<code>public class Customer {
  @Email
  private String email;
  @NotBlank
  private String name;
  // other fields
}</code>

Controller method:

<code>@RestController
public class ValidateRequestBodyController {
  @PostMapping("/body")
  public ResponseEntity<String> body(@Valid @RequestBody Input input) {
    return ResponseEntity.ok("valid");
  }
}</code>

Unit test demonstrates a 400 response when validation fails.

2.3 Service‑Layer Validation

Apply @Validated at the class level and @Valid on method parameters to validate non‑controller beans:

<code>@Service
@Validated
public class ValidatingService {
  public void validateInput(@Valid Input input) {
    // business logic
  }
}</code>

2.4 JPA Entity Validation

Hibernate validates entity fields during persistence. Example entity:

<code>@Entity
public class Dog {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @NotEmpty
  private String name;
}</code>

Saving an invalid entity throws ConstraintViolationException . Validation can be disabled via:

<code>spring:
  jpa:
    properties:
      '[javax.persistence.validation.mode]': none</code>

2.5 Custom Validation Annotations

Define a constraint annotation with @Constraint and implement ConstraintValidator :

<code>@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PrefixConstraintValidator.class)
public @interface PrefixConstraint {
  String value() default "";
  String message() default "{validator.prefix.error}";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}</code>

Validator implementation:

<code>public class PrefixConstraintValidator implements ConstraintValidator<PrefixConstraint, CharSequence> {
  private String prefix;
  @Override
  public void initialize(PrefixConstraint pc) { prefix = pc.value(); }
  @Override
  public boolean isValid(CharSequence value, ConstraintValidatorContext ctx) {
    return value != null && value.toString().startsWith(prefix);
  }
}</code>

2.6 Programmatic Validation

Use the Bean Validation API directly when you need explicit validation:

<code>ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Dog>> violations = validator.validate(new Dog());
if (!violations.isEmpty()) {
  throw new ConstraintViolationException(violations);
}</code>

2.7 Validation Groups

Define marker interfaces (e.g., G1 , G2 ) and assign them to constraints to apply different rules in different scenarios:

<code>public interface G1 {}
public interface G2 {}

public class User {
  @Min(1) @Max(150)
  private Integer age;
  @NotEmpty(groups = G1.class)
  private String name;
  @NotEmpty(groups = G2.class)
  private String address;
}</code>

Controller methods can trigger specific groups with @Validated(G1.class) or @Validated(G2.class) .

2.8 Validation Error Handling

Two approaches to return meaningful error information:

Inject BindingResult after the validated object and build a custom response.

Define a global @RestControllerAdvice that catches MethodArgumentNotValidException or ConstraintViolationException and formats the errors.

<code>@RestControllerAdvice
public class GlobalExceptionHandler {
  @ExceptionHandler(Exception.class)
  public R globalException(Exception ex) {
    if (ex instanceof MethodArgumentNotValidException e) {
      List<String> errs = e.getFieldErrors().stream()
        .map(err -> err.getField() + ", " + err.getDefaultMessage())
        .collect(Collectors.toList());
      return R.error(errs);
    }
    return R.error("Unexpected error");
  }
}</code>

2.9 Internationalized Error Messages

Specify messages directly with message="..." or use placeholders that refer to keys in messages_zh_CN.properties and messages_en_US.properties . Spring loads these files via the spring.messages.basename property.

<code>@NotEmpty(message = "{name.empty.error}")
private String name;
</code>

2.10 Custom Validation Annotation Usage

Annotations whose name starts with Valid (or are meta‑annotated with @Validated ) are automatically processed by Spring MVC. Example:

<code>@Retention(RUNTIME)
@Target(PARAMETER)
public @interface ValidPack {}

@PostMapping("/save")
public R save(@RequestBody @ValidPack User user) {
  return R.success(user);
}</code>

The article concludes with a reminder to like, share, and collect the content.

JavaBean ValidationSpring MVCInternationalizationJPAspring-bootvalidation-annotations
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.