or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin-jmx.mdansi-support.mdaot-native-image.mdapplication-info.mdavailability.mdbootstrap.mdbootstrapping.mdbuilder.mdcloud-platform.mdconfiguration-annotations.mdconfiguration-data.mdconfiguration-properties.mdconversion.mddiagnostics.mdenvironment-property-sources.mdindex.mdjson-support.mdlifecycle-events.mdlogging.mdorigin-tracking.mdresource-loading.mdretry-support.mdssl-tls.mdstartup-metrics.mdsupport.mdsystem-utilities.mdtask-execution.mdthreading.mdutilities.mdvalidation.mdweb-support.md
tile.json

validation.mddocs/

Spring Boot Validation Package

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.

Message Interpolation

MessageInterpolatorFactory

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:

  • Automatically selects the best available MessageInterpolator from the classpath
  • Falls back to ParameterMessageInterpolator if the default provider is not available
  • Optionally wraps interpolator with MessageSource support for i18n

Example:

// 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();
}

MessageSourceMessageInterpolator

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:

  • Resolves {messageKey} placeholders through MessageSource
  • Supports recursive parameter replacement
  • Detects circular references
  • Escaping with backslash: \{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;

Method Validation Filtering

MethodValidationExcludeFilter

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");

FilteredMethodValidationPostProcessor

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);
    }
}

Usage Examples

Setting Up Validation with MessageSource

@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;
    }
}

Creating Validation Messages

# 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} liegen

Using Custom Validation with Messages

public 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
}

Excluding Controllers from Method Validation

@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))
        );
    }
}

Combining Multiple Exclusion Filters

@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 with Method Validation

@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;
    }
}

Programmatic Validation with Custom Interpolator

@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(", "))
            );
        }
    }
}

Integration with Spring Boot Auto-Configuration

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 Statements

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;