Backend Development 8 min read

Master Spring Validation in Spring Boot 2.6: From Basics to Custom Annotations

This guide explains Spring Validation in Spring Boot 2.6, covering its lightweight features, configuration of Bean Validation providers, injection of validators, practical examples, custom annotation creation, method‑level validation, and additional configuration options with clear code samples.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Validation in Spring Boot 2.6: From Basics to Custom Annotations

Introduction

Spring Validation is a lightweight data‑validation framework for Java objects, offering a unified API, annotation‑based constraints, nested and group validation, internationalization, and extensibility through custom validators. It integrates with Hibernate Validator by default.

Key Features

Lightweight – focuses solely on validation.

Simple to use – annotation‑driven and easy to maintain.

Flexible rules – supports custom constraints.

Internationalization – provides locale‑specific messages.

Hibernate Validator integration – works seamlessly with other validation frameworks.

Bean Validation Basics

Declare constraints on POJO fields using annotations such as @NotNull , @Size , and @Min :

<code>public class Person {
  @NotNull
  @Size(max=64)
  private String name;

  @Min(0)
  private int age;
}</code>

The Bean Validation engine validates instances against these constraints at runtime.

Configuring a Bean Validation Provider

Spring can expose a javax.validation.ValidatorFactory or javax.validation.Validator as beans. The typical configuration uses LocalValidatorFactoryBean :

<code>import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class AppConfig {

  @Bean
  public LocalValidatorFactoryBean validator() {
    return new LocalValidatorFactoryBean();
  }
}
</code>

Injecting Validators

<code>@Service
public class PersonService {
  // Java EE validator
  @Resource
  private Validator validator;

  // Spring validator
  @Resource
  private org.springframework.validation.Validator springValidator;
}
</code>

Simple Validation Example

<code>@Service
public class PersonService {

  @Resource
  private Validator validator;

  @Resource
  private org.springframework.validation.Validator springValidator;

  public void validate(Person person) {
    Set&lt;ConstraintViolation&lt;Person&gt;&gt; violations = validator.validate(person);
    violations.forEach(cv -> System.out.println(cv.getMessage()));
    System.out.println("----------------------");
    BindingResult errors = new MapBindingResult(new HashMap&lt;String, Object&gt;(), "person");
    springValidator.validate(person, errors);
    if (errors.hasErrors()) {
      errors.getAllErrors().forEach(e -> System.out.println(e.getDefaultMessage()));
    }
  }
}
</code>

Test Case

<code>@SpringBootTest
class SpringBootValidationApplicationTests {

  @Resource
  private PersonService ps;

  @Test
  public void testValidator() {
    Person person = new Person();
    person.setAge(-1);
    ps.validate(person);
  }
}
</code>
<code>Minimum value must not be less than 0
must not be null
----------------------
Minimum value must not be less than 0
must not be null</code>

Custom Annotation Validation

A custom constraint consists of an annotation marked with @Constraint and a validator implementing 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>

The validator can inject other beans and contain custom logic:

<code>public class PrefixConstraintValidator implements ConstraintValidator&lt;PrefixConstraint, CharSequence&gt; {

  @Resource
  private DataService ds;

  private String prefix;

  @Override
  public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
    ds.ak();
    if (value == null) {
      return false;
    }
    return ((String) value).startsWith(prefix);
  }

  @Override
  public void initialize(PrefixConstraint pc) {
    prefix = pc.value();
  }
}
</code>

Method‑Level Validation

Enable method validation by registering MethodValidationPostProcessor and annotating beans with @Validated :

<code>@Bean
public MethodValidationPostProcessor validationPostProcessor() {
  return new MethodValidationPostProcessor();
}

@Service
@Validated
public class PersonService {

  @NotNull(message = "Return value cannot be null")
  public Person findPerson(@NotEmpty(message = "ID cannot be empty") String id) {
    return null;
  }
}
</code>

The class must carry @Validated for the post‑processor to apply the advice.

Testing Method Validation

The thrown javax.validation.ConstraintViolationException should be handled globally via an exception interceptor.

Other Configuration Options

The default LocalValidatorFactoryBean configuration is sufficient for most cases, but you can customize message interpolation, traversal, and other settings. See the Javadoc for details.

https://docs.spring.io/spring-framework/docs/5.3.11/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html

End of tutorial.

Javabackend developmentBean ValidationValidationSpring Bootcustom 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.