docs
Package: org.springframework.boot.validation
The validation package provides utilities and classes for Bean Validation (JSR-380) integration with Spring Boot, including message interpolation and method validation filtering.
Factory for creating MessageInterpolator instances with automatic fallback support.
public class MessageInterpolatorFactory implements ObjectFactory<MessageInterpolator> {
public MessageInterpolatorFactory();
public MessageInterpolatorFactory(MessageSource messageSource);
@Override
public MessageInterpolator getObject() throws BeansException;
}Features:
MessageInterpolator from the classpathParameterMessageInterpolator if the default provider is not availableMessageSource support for i18nExample:
// Basic usage
MessageInterpolatorFactory factory = new MessageInterpolatorFactory();
MessageInterpolator interpolator = factory.getObject();
// With MessageSource for i18n support
@Bean
public MessageInterpolator messageInterpolator(MessageSource messageSource) {
return new MessageInterpolatorFactory(messageSource).getObject();
}Resolves message parameters through MessageSource before final interpolation, enabling Spring i18n integration.
class MessageSourceMessageInterpolator implements MessageInterpolator {
MessageSourceMessageInterpolator(
MessageSource messageSource,
MessageInterpolator messageInterpolator);
@Override
public String interpolate(String messageTemplate, Context context);
@Override
public String interpolate(String messageTemplate, Context context, Locale locale);
}Features:
{messageKey} placeholders through MessageSource\{escaped\} → {escaped}Example:
// messages.properties
validation.email.invalid=The email address is not valid
validation.size.min=Must be at least {min} characters
// Validation annotation
@Email(message = "{validation.email.invalid}")
private String email;
@Size(min = 5, message = "{validation.size.min}")
private String username;Interface for excluding types from method validation based on custom criteria.
@FunctionalInterface
public interface MethodValidationExcludeFilter {
boolean isExcluded(Class<?> type);
static MethodValidationExcludeFilter byAnnotation(
Class<? extends Annotation> annotationType);
static MethodValidationExcludeFilter byAnnotation(
Class<? extends Annotation> annotationType,
SearchStrategy searchStrategy);
}Factory Methods:
byAnnotation(Class) - Exclude types with annotation (inherited search)byAnnotation(Class, SearchStrategy) - Exclude types with annotation (custom search strategy)Example:
// Exclude all @RestController classes from method validation
MethodValidationExcludeFilter filter =
MethodValidationExcludeFilter.byAnnotation(RestController.class);
// Custom implementation
MethodValidationExcludeFilter customFilter = type ->
type.getPackageName().startsWith("com.example.legacy");Custom method validation post-processor that applies exclusion filters.
public class FilteredMethodValidationPostProcessor
extends MethodValidationPostProcessor {
public FilteredMethodValidationPostProcessor(
Stream<? extends MethodValidationExcludeFilter> excludeFilters);
public FilteredMethodValidationPostProcessor(
Collection<? extends MethodValidationExcludeFilter> excludeFilters);
@Override
public void afterPropertiesSet();
}Example:
@Configuration
public class ValidationConfig {
@Bean
public FilteredMethodValidationPostProcessor methodValidationPostProcessor() {
// Exclude multiple types from method validation
List<MethodValidationExcludeFilter> filters = List.of(
MethodValidationExcludeFilter.byAnnotation(RestController.class),
MethodValidationExcludeFilter.byAnnotation(Controller.class),
type -> type.getName().contains("Internal")
);
return new FilteredMethodValidationPostProcessor(filters);
}
}@Configuration
public class ValidationConfiguration {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource =
new ResourceBundleMessageSource();
messageSource.setBasename("validation-messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource);
return validator;
}
}# validation-messages.properties
user.email.invalid=Please provide a valid email address
user.password.weak=Password must contain at least {min} characters
user.age.range=Age must be between {min} and {max}
# validation-messages_de.properties (German)
user.email.invalid=Bitte geben Sie eine gültige E-Mail-Adresse an
user.password.weak=Das Passwort muss mindestens {min} Zeichen enthalten
user.age.range=Das Alter muss zwischen {min} und {max} liegenpublic class User {
@NotNull(message = "{user.email.invalid}")
@Email(message = "{user.email.invalid}")
private String email;
@Size(min = 8, message = "{user.password.weak}")
private String password;
@Min(value = 18, message = "{user.age.range}")
@Max(value = 120, message = "{user.age.range}")
private int age;
// Getters and setters
}@Configuration
public class MethodValidationConfig {
@Bean
public FilteredMethodValidationPostProcessor methodValidationPostProcessor() {
// Don't validate methods in REST controllers
// (request body validation is handled separately)
return new FilteredMethodValidationPostProcessor(
List.of(MethodValidationExcludeFilter.byAnnotation(RestController.class))
);
}
}@Configuration
public class AdvancedValidationConfig {
@Bean
public FilteredMethodValidationPostProcessor methodValidationPostProcessor() {
Stream<MethodValidationExcludeFilter> filters = Stream.of(
// Exclude by annotation
MethodValidationExcludeFilter.byAnnotation(RestController.class),
MethodValidationExcludeFilter.byAnnotation(NoValidation.class),
// Exclude by package
type -> type.getPackageName().startsWith("com.example.legacy"),
// Exclude by naming convention
type -> type.getSimpleName().endsWith("Internal"),
// Exclude interfaces
Class::isInterface
);
return new FilteredMethodValidationPostProcessor(filters);
}
}
// Custom marker annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface NoValidation {
}@Service
@Validated
public class UserService {
// Method parameters will be validated
public void createUser(
@Valid @NotNull User user,
@NotBlank @Email String notificationEmail) {
// Implementation
}
// Return value will be validated
@NotNull
public User findUser(@NotNull @Min(1) Long id) {
// Implementation
return user;
}
}@Component
public class ValidationHelper {
private final Validator validator;
public ValidationHelper(MessageSource messageSource) {
MessageInterpolatorFactory factory =
new MessageInterpolatorFactory(messageSource);
MessageInterpolator interpolator = factory.getObject();
Configuration<?> configuration = Validation
.byDefaultProvider()
.configure()
.messageInterpolator(interpolator);
ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
this.validator = validatorFactory.getValidator();
}
public <T> Set<ConstraintViolation<T>> validate(T object) {
return validator.validate(object);
}
public void validateAndThrow(Object object) {
Set<ConstraintViolation<Object>> violations = validator.validate(object);
if (!violations.isEmpty()) {
throw new ValidationException(
violations.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining(", "))
);
}
}
}Spring Boot automatically configures validation when hibernate-validator is on the classpath:
<!-- Maven dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>// Gradle dependency
implementation 'org.springframework.boot:spring-boot-starter-validation'import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
import jakarta.validation.MessageInterpolator;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import jakarta.validation.Validation;
import org.springframework.context.MessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.annotation.Validated;