Skip to content

Instantly share code, notes, and snippets.

@daniel-shuy
Last active May 21, 2020 13:07
Show Gist options
  • Save daniel-shuy/0e877ce1881858bc551bcb9ee7a0a26d to your computer and use it in GitHub Desktop.
Save daniel-shuy/0e877ce1881858bc551bcb9ee7a0a26d to your computer and use it in GitHub Desktop.
Spring Boot: Map Hibernate Validator ConstraintValidator to `@Constraint` annotation without having both in the same project

A @Constraint annotation is normally mapped to ConstraintValidator(s) using the @Constraint#validatedBy annotation parameter.

This however has the limitation that the @Constraint annotation has to know about the ConstraintValidator(s) during compilation, which may not always be feasible (for example, if the annotation is used at the DTO layer, but a ConstraintValidator depends on the service layer, and the DTO layer is in a separate JAR file).

Most examples will simply create a new Validator bean, which will override the one created by Spring Boot.

The ValidationConfigurerAdapter abstract class provided can be extended as a @Configuration to have the same behavior as Spring Boot's ValidationAutoConfiguration, but allows the mapping of @Constraint annotations to ConstraintValidators to be defined by overriding the mapConstraints(ConstraintMapping) method. See https://docs.jboss.org/hibernate/validator/6.0/reference/en-US/html_single/#section-programmatic-constraint-definition for instructions on how to configure the mappings programmatically.

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
import javax.validation.Configuration;
import javax.validation.Constraint;
import javax.validation.Validator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
/**
* Provides a convenient base class for creating a {@link org.springframework.context.annotation.Configuration} to map
* {@link Constraint} annotations to validators for Hibernate Validator.
*
* @see ValidationAutoConfiguration
**/
public abstract class ValidationConfigurerAdapter {
protected void mapConstraints(ConstraintMapping constraintMapping);
@Bean
public Validator validator() {
var factoryBean = new LocalValidatorFactoryBean() {
@Override
protected void postProcessConfiguration(Configuration<?> configuration) {
if (configuration instanceof HibernateValidatorConfiguration) {
var hibernateValidatorConfiguration = (HibernateValidatorConfiguration) configuration;
var constraintMapping = hibernateValidatorConfiguration.createConstraintMapping();
mapConstraints(constraintMapping);
hibernateValidatorConfiguration.addMapping(constraintMapping);
}
}
};
var interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment