skip to content

Bean Validation (JSR-380) Integration

Wiring Jakarta Bean Validation into Spring gives you a shared Validator and, with @Validated, constraint checking on method parameters and return values. Interviewers probe the difference between validating an object and validating a method call.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Bean Validation (JSR-380) and how does Spring expose a Jakarta Validator you can inject?

level: juniorimportance: must knowfreq 60%

answer

  1. jakarta.validation.Validator
  2. LocalValidatorFactoryBean = 3 interfaces
  3. validate() returns Set<ConstraintViolation>
  4. starter-validation = Hibernate Validator
  5. factory bean -> DI-able custom validators

basics

~10 s

Bean Validation is a standard for declaring rules on fields with annotations like @NotNull and @Size. Spring's LocalValidatorFactoryBean builds a Validator you can inject and call validate() on.

solid answer

~40 s

Bean Validation (JSR-380 / Jakarta Validation) is a specification for expressing constraints on object fields and methods using annotations such as @NotNull, @Size, @Email, and @Min; a provider like Hibernate Validator enforces them. Spring integrates it via LocalValidatorFactoryBean, which implements both the Jakarta jakarta.validation.Validator and Spring's own org.springframework.validation.Validator. Boot auto-configures this bean when a provider is on the classpath (spring-boot-starter-validation). You inject jakarta.validation.Validator and call validate(obj), getting back a Set<ConstraintViolation<T>>; each violation carries the message, property path, and invalid value. An empty set means valid. The key advantage of the Spring-managed factory bean over building a ValidatorFactory yourself is that it makes custom ConstraintValidators Spring beans, so they can be dependency-injected.

code

java · 21 lines
java
import jakarta.validation.Validator;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.constraints.*;
import org.springframework.stereotype.Service;
import java.util.Set;

class Order {
    @NotBlank String customer;
    @Min(1) int quantity;
}

@Service
class OrderChecker {
    private final Validator validator; // jakarta.validation.Validator
    OrderChecker(Validator validator) { this.validator = validator; }

    boolean isValid(Order order) {
        Set<ConstraintViolation<Order>> v = validator.validate(order);
        return v.isEmpty(); // no exception thrown; inspect v for messages
    }
}

go deeper

for a junior

Know the common constraint annotations and that LocalValidatorFactoryBean gives an injectable Validator whose validate() returns violations.

for a middle

Explain the spec-vs-provider split and that Boot auto-configures the factory bean; know validate() doesn't throw.

for a senior

Explain the three interfaces LocalValidatorFactoryBean implements and why the Spring factory bean enables DI into custom validators.

for a principal

Discuss SpringConstraintValidatorFactory, MessageSource interpolation wiring, and when programmatic vs declarative validation is architecturally right.

**Bean Validation** (originally JSR-303, then JSR-349, then JSR-380 for Bean Validation 2.0, now branded **Jakarta Validation**) is a Java specification for declaring and enforcing **constraints** on object state. You annotate fields, getters, method parameters, or return values with **constraint annotations** and a runtime **provider** checks them. **Provider vs spec:** The spec lives in the `jakarta.validation` package (`jakarta.validation.Validator`, `jakarta.validation.ConstraintViolation`, the annotations in `jakarta.validation.constraints.*`). The most common implementation is **Hibernate Validator** (unrelated to Hibernate ORM). You need both on the classpath; `spring-boot-starter-validation` pulls them in. **Standard constraints** include `@NotNull` (not null), `@NotBlank` (non-null, non-whitespace string), `@NotEmpty` (non-empty collection/string), `@Size(min, max)`, `@Min`/`@Max`, `@Positive`, `@Email`, `@Pattern(regexp=...)`, `@Past`/`@Future`, `@Digits`, and `@DecimalMin`. **How Spring exposes a Validator:** `org.springframework.validation.beanvalidation.LocalValidatorFactoryBean` is a Spring `FactoryBean` that bootstraps a Jakarta `ValidatorFactory` and adapts it. Crucially it implements **three** interfaces at once: `jakarta.validation.ValidatorFactory`, `jakarta.validation.Validator`, and Spring's older `org.springframework.validation.Validator`. So you can inject it as any of those. In Spring Boot, `ValidationAutoConfiguration` registers a `LocalValidatorFactoryBean` automatically (named `defaultValidator`) whenever a Bean Validation provider is present and no other `Validator` bean is defined. **Programmatic use:** ```java @Autowired jakarta.validation.Validator validator; Set<ConstraintViolation<Order>> violations = validator.validate(order); ``` Each `ConstraintViolation` exposes `getMessage()`, `getPropertyPath()`, `getInvalidValue()`, and the constraint descriptor. An **empty set** means the object satisfied all constraints. Programmatic `validate()` does **not** throw — it returns violations; you decide what to do. **Why the Spring factory bean matters:** If you built a `ValidatorFactory` yourself via `Validation.buildDefaultValidatorFactory()`, any custom `ConstraintValidator` would be instantiated by the provider with no access to the Spring context. `LocalValidatorFactoryBean` installs a `SpringConstraintValidatorFactory`, so your custom validators become **Spring-managed** and can `@Autowired` other beans (e.g., a repository to check uniqueness). It also wires a `MessageSource` for message interpolation and can be told the constraint mappings. **Gotchas:** (1) Injecting `org.springframework.validation.Validator` vs `jakarta.validation.Validator` — the same bean satisfies both, but pick the type your code needs. (2) Validation is **not automatic** on plain bean method calls just because fields are annotated — programmatic `validate()` or the `@Validated` method-validation mechanism must trigger it. (3) `@Valid` on a nested field triggers **cascade** validation into that object graph. **When to use programmatic validation:** service-layer checks where you want to inspect violations without an exception, batch validation, or conditional flows. For declarative method validation prefer `@Validated` + `MethodValidationPostProcessor` (a sibling concept covered separately).

  • Does calling validator.validate() throw when the object is invalid?
    No. Programmatic validate() returns a Set<ConstraintViolation>; an empty set means valid. It never throws for constraint failures — the caller decides. Only the @Validated method-validation path throws ConstraintViolationException.
  • Why prefer LocalValidatorFactoryBean over Validation.buildDefaultValidatorFactory()?
    The Spring factory bean uses a SpringConstraintValidatorFactory, so custom ConstraintValidators are Spring beans and can @Autowired dependencies; it also hooks Spring's MessageSource for message interpolation.

saying these in an interview costs you the question

  • Thinking annotating fields alone validates them automatically on any method call
  • Claiming validate() throws an exception on invalid input
  • Confusing Hibernate Validator with Hibernate ORM
  • Assuming you must build the ValidatorFactory manually in Spring Boot

context

open as a page

How does @Validated enable method-level validation on Spring beans, and what makes it work?

level: middleimportance: must knowfreq 65%

basics

~20 s

Put @Validated on a bean's class; then constraint annotations on its method parameters (like @NotNull) and return values are enforced on every call. A MethodValidationPostProcessor creates an AOP proxy that checks them and throws ConstraintViolationException on failure.

open as a page

How do you write a custom constraint with a ConstraintValidator, and how can it use Spring beans?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Create an annotation meta-annotated with @Constraint pointing at a class implementing ConstraintValidator<A, T>. Put the logic in isValid(). Because Spring's LocalValidatorFactoryBean creates validators as Spring beans, you can @Autowired dependencies like a repository into it.

open as a page

What are validation groups and how do you use them with Spring's @Validated?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Validation groups let you apply different subsets of constraints in different situations. You tag constraints with a group marker interface, then activate that group — with Spring you pass the group class to @Validated(MyGroup.class) — so only those constraints run.

open as a page

How is Bean Validation wired in a Spring context, and what configuration/lifecycle pitfalls should you know as a principal engineer?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Spring Boot auto-registers a LocalValidatorFactoryBean (the injectable Validator) and a MethodValidationPostProcessor (for @Validated method validation). You can override them to customize the message source, constraint validator factory, or bootstrap options. Watch proxying, message interpolation, and validator statelessness.

open as a page