Spring-Boot
Dependency Injection
javax.validation.Validator
Java
Software Development

Spring-Boot How to properly inject javax.validation.Validator

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

Introduction

In Spring Boot, you normally inject the Bean Validation Validator as a regular Spring bean rather than creating it yourself. The main complication is versioning: Spring Boot 2 uses javax.validation.Validator, while Spring Boot 3 uses jakarta.validation.Validator.

Let Spring Boot Create the Validator

If the validation starter is on the classpath, Spring Boot usually auto-configures a validator for you.

Maven:

xml
1<dependency>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-validation</artifactId>
4</dependency>

That gives you a LocalValidatorFactoryBean behind the scenes and exposes it through the validation interface. In a Boot 2 application, that means you can inject javax.validation.Validator directly.

java
1import java.util.Set;
2import javax.validation.ConstraintViolation;
3import javax.validation.Validator;
4import org.springframework.stereotype.Service;
5
6@Service
7public class RegistrationValidationService {
8    private final Validator validator;
9
10    public RegistrationValidationService(Validator validator) {
11        this.validator = validator;
12    }
13
14    public Set<ConstraintViolation<RegistrationRequest>> validate(RegistrationRequest request) {
15        return validator.validate(request);
16    }
17}

Constructor injection is the right default because the dependency is explicit and testable.

javax.validation Versus jakarta.validation

The package name matters.

If you are on:

  • Spring Boot 2.x, inject javax.validation.Validator
  • Spring Boot 3.x, inject jakarta.validation.Validator

The usage pattern is almost identical, but the import is not.

That means code copied from older blog posts can fail to compile after a Boot 3 upgrade even if the surrounding logic is still correct.

Manual Validation Versus Automatic Validation

There are two common validation styles in Spring Boot.

Automatic request validation

java
1import javax.validation.Valid;
2import javax.validation.constraints.NotBlank;
3import org.springframework.web.bind.annotation.PostMapping;
4import org.springframework.web.bind.annotation.RequestBody;
5import org.springframework.web.bind.annotation.RestController;
6
7class RegistrationRequest {
8    @NotBlank
9    private String email;
10
11    public String getEmail() {
12        return email;
13    }
14
15    public void setEmail(String email) {
16        this.email = email;
17    }
18}
19
20@RestController
21class RegistrationController {
22    @PostMapping("/register")
23    public String register(@Valid @RequestBody RegistrationRequest request) {
24        return "ok";
25    }
26}

This is ideal when validation belongs at the HTTP boundary.

Manual validation in service code

java
1Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
2if (!violations.isEmpty()) {
3    throw new IllegalArgumentException(violations.iterator().next().getMessage());
4}

This is useful when validation needs to happen:

  • outside controllers
  • in batch workflows
  • in event handlers
  • before calling deeper business logic

Do Not Build the Validator Manually Unless Necessary

A lot of examples online show direct factory creation. In Boot, that is usually unnecessary.

Avoid doing this unless you have a specific customization need:

java
// usually unnecessary in Spring Boot application code
// ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
// Validator validator = factory.getValidator();

That bypasses Spring's configuration model and can make testing or message configuration less consistent.

If you really need custom validator setup, define a bean intentionally.

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
4
5@Configuration
6public class ValidationConfig {
7    @Bean
8    public LocalValidatorFactoryBean validatorFactoryBean() {
9        return new LocalValidatorFactoryBean();
10    }
11}

But do this only when you need specific behavior such as message-source integration or custom constraint wiring.

Method Validation Is Separate

Spring can also validate method parameters on beans when method validation is enabled.

java
1import javax.validation.constraints.NotBlank;
2import org.springframework.stereotype.Service;
3import org.springframework.validation.annotation.Validated;
4
5@Validated
6@Service
7public class GreetingService {
8    public String greet(@NotBlank String name) {
9        return "Hello " + name;
10    }
11}

That does not replace injected Validator, but it is powered by the same validation infrastructure.

Choose the style based on where the rule belongs, not just on which API looks shorter.

Common Pitfalls

  • Injecting javax.validation.Validator in a Spring Boot 3 project that uses jakarta.validation.Validator.
  • Creating a validator manually when Boot already provides one.
  • Using field injection instead of constructor injection, which makes tests and dependencies less explicit.
  • Expecting @Valid to handle validation in arbitrary service methods without method validation support.
  • Overriding the default validator bean without a clear reason.

Summary

  • In Spring Boot, the validator is usually auto-configured for you.
  • Inject Validator through the constructor instead of building it manually.
  • Use javax.validation on Boot 2 and jakarta.validation on Boot 3.
  • Prefer automatic validation at boundaries and manual validation where business flow requires it.
  • Customize the validator bean only when you have a concrete need.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

All Rights Reserved.