Skip to content

Commit

Permalink
Hibernate Validator - Allow customization of the ValidatorFactory
Browse files Browse the repository at this point in the history
Signed-off-by: Theodor Mihalache <[email protected]>
  • Loading branch information
tmihalac authored and gsmet committed Jul 12, 2022
1 parent 19cba3c commit a814636
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import io.quarkus.deployment.logging.LogCleanupFilterBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.hibernate.validator.HibernateValidatorFactoryCustomizer;
import io.quarkus.hibernate.validator.runtime.DisableLoggingFeature;
import io.quarkus.hibernate.validator.runtime.HibernateValidatorBuildTimeConfig;
import io.quarkus.hibernate.validator.runtime.HibernateValidatorRecorder;
Expand Down Expand Up @@ -108,6 +109,9 @@ class HibernateValidatorProcessor {
private static final DotName PROPERTY_NODE_NAME_PROVIDER = DotName
.createSimple(PropertyNodeNameProvider.class.getName());

private static final DotName CONSTRAINT_MAPPING_PROVIDER = DotName
.createSimple(HibernateValidatorFactoryCustomizer.class.getName());

private static final DotName CONSTRAINT_VALIDATOR = DotName.createSimple(ConstraintValidator.class.getName());
private static final DotName VALUE_EXTRACTOR = DotName.createSimple(ValueExtractor.class.getName());

Expand Down Expand Up @@ -187,7 +191,8 @@ public boolean test(BeanInfo beanInfo) {
|| beanInfo.hasType(VALUE_EXTRACTOR) || beanInfo.hasType(SCRIPT_EVALUATOR_FACTORY)
|| beanInfo.hasType(GETTER_PROPERTY_SELECTION_STRATEGY)
|| beanInfo.hasType(LOCALE_RESOLVER)
|| beanInfo.hasType(PROPERTY_NODE_NAME_PROVIDER);
|| beanInfo.hasType(PROPERTY_NODE_NAME_PROVIDER)
|| beanInfo.hasType(CONSTRAINT_MAPPING_PROVIDER);
}
}));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import static org.assertj.core.api.Assertions.assertThat;

import javax.inject.Inject;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

public class HibernateValidatorFactoryCustomizerTest {

@Inject
ValidatorFactory validatorFactory;

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap
.create(JavaArchive.class)
.addClasses(MyMultipleHibernateValidatorFactoryCustomizer.class, MyEmailValidator.class,
MyNumValidator.class));

@Test
public void testOverrideConstraintValidatorConstraint() {
assertThat(validatorFactory.getValidator().validate(new TestBean())).hasSize(2);
}

static class TestBean {
@Email
public String email;

@Min(-1)
public int num;

public TestBean() {
this.email = "[email protected]";
this.num = -1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import static org.assertj.core.api.Assertions.assertThat;

import javax.inject.Inject;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

public class MultipleHibernateFactoryCustomizersTest {

@Inject
ValidatorFactory validatorFactory;

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap
.create(JavaArchive.class)
.addClasses(MyEmailHibernateValidatorFactoryCustomizer.class, MyNumberHibernateValidatorFactoryCustomizer.class,
MyEmailValidator.class,
MyNumValidator.class));

@Test
public void testOverrideConstraintValidatorConstraint() {
assertThat(validatorFactory.getValidator().validate(new TestBean())).hasSize(2);
}

static class TestBean {
@Email
public String email;

@Min(-1)
public int num;

public TestBean() {
this.email = "[email protected]";
this.num = -1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import javax.enterprise.context.ApplicationScoped;
import javax.validation.constraints.Email;

import org.hibernate.validator.BaseHibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;

import io.quarkus.hibernate.validator.HibernateValidatorFactoryCustomizer;

@ApplicationScoped
public class MyEmailHibernateValidatorFactoryCustomizer implements HibernateValidatorFactoryCustomizer {

@Override
public <T extends BaseHibernateValidatorConfiguration<T>> void customize(T configuration) {
ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
.constraintDefinition(Email.class)
.includeExistingValidators(false)
.validatedBy(MyEmailValidator.class);

configuration.addMapping(constraintMapping);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraints.Email;

public class MyEmailValidator implements ConstraintValidator<Email, CharSequence> {
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return "[email protected]".contentEquals(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import javax.enterprise.context.ApplicationScoped;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;

import org.hibernate.validator.BaseHibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;

import io.quarkus.hibernate.validator.HibernateValidatorFactoryCustomizer;

@ApplicationScoped
public class MyMultipleHibernateValidatorFactoryCustomizer implements HibernateValidatorFactoryCustomizer {

@Override
public <T extends BaseHibernateValidatorConfiguration<T>> void customize(T configuration) {
ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
.constraintDefinition(Email.class)
.includeExistingValidators(false)
.validatedBy(MyEmailValidator.class);

configuration.addMapping(constraintMapping);

constraintMapping = configuration.createConstraintMapping();

constraintMapping
.constraintDefinition(Min.class)
.includeExistingValidators(false)
.validatedBy(MyNumValidator.class);

configuration.addMapping(constraintMapping);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraints.Min;

public class MyNumValidator implements ConstraintValidator<Min, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return value >= 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.quarkus.hibernate.validator.test.validatorfactory;

import javax.enterprise.context.ApplicationScoped;
import javax.validation.constraints.Min;

import org.hibernate.validator.BaseHibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;

import io.quarkus.hibernate.validator.HibernateValidatorFactoryCustomizer;

@ApplicationScoped
public class MyNumberHibernateValidatorFactoryCustomizer implements HibernateValidatorFactoryCustomizer {

@Override
public <T extends BaseHibernateValidatorConfiguration<T>> void customize(T configuration) {
ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
.constraintDefinition(Min.class)
.includeExistingValidators(false)
.validatedBy(MyNumValidator.class);

configuration.addMapping(constraintMapping);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.hibernate.validator;

import org.hibernate.validator.BaseHibernateValidatorConfiguration;

/**
* Meant to be implemented by a CDI bean that provides arbitrary customization for the default
* {@link javax.validation.ValidatorFactory}.
* <p>
* All implementations that are registered as CDI beans are taken into account when producing the default
* {@link javax.validation.ValidatorFactory}.
* <p>
* Customizers are applied in the order of {@link javax.annotation.Priority}.
*/
public interface HibernateValidatorFactoryCustomizer {

<T extends BaseHibernateValidatorConfiguration<T>> void customize(T configuration);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.hibernate.validator.runtime;

import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

Expand All @@ -25,6 +26,7 @@
import io.quarkus.arc.InstanceHandle;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.runtime.BeanContainerListener;
import io.quarkus.hibernate.validator.HibernateValidatorFactoryCustomizer;
import io.quarkus.hibernate.validator.runtime.jaxrs.ResteasyConfigSupport;
import io.quarkus.runtime.LocalesBuildTimeConfig;
import io.quarkus.runtime.ShutdownContext;
Expand Down Expand Up @@ -148,6 +150,15 @@ public void created(BeanContainer container) {
configuration.addValueExtractor(valueExtractor);
}

List<InstanceHandle<HibernateValidatorFactoryCustomizer>> constraintMappingProviderList = Arc.container()
.listAll(HibernateValidatorFactoryCustomizer.class);
for (InstanceHandle<HibernateValidatorFactoryCustomizer> cmpInstanceHandle : constraintMappingProviderList) {
if (cmpInstanceHandle.isAvailable()) {
final HibernateValidatorFactoryCustomizer hibernateValidatorFactoryCustomizer = cmpInstanceHandle.get();
hibernateValidatorFactoryCustomizer.customize(configuration);
}
}

ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
ValidatorHolder.initialize(validatorFactory);

Expand Down

0 comments on commit a814636

Please sign in to comment.