Skip to content

Commit 4cb8d13

Browse files
marko-bekhtagsmet
authored andcommitted
HV-1363 Added ability to configure property filter for ValidatorFactory
1 parent c63b86e commit 4cb8d13

File tree

8 files changed

+331
-17
lines changed

8 files changed

+331
-17
lines changed

engine/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java

+22
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.hibernate.validator.cfg.ConstraintMapping;
2121
import org.hibernate.validator.constraints.ParameterScriptAssert;
2222
import org.hibernate.validator.constraints.ScriptAssert;
23+
import org.hibernate.validator.spi.properties.GetterPropertyMatcher;
2324
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
2425
import org.hibernate.validator.spi.scripting.ScriptEvaluator;
2526
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
@@ -107,6 +108,15 @@ public interface HibernateValidatorConfiguration extends Configuration<Hibernate
107108
@Incubating
108109
String TEMPORAL_VALIDATION_TOLERANCE = "hibernate.validator.temporal_validation_tolerance";
109110

111+
/**
112+
* Property for configuring the getter property matcher, allowing to set which rules will be applied
113+
* to determine if a method is a valid JavaBean getter.
114+
*
115+
* @since 6.1.0
116+
*/
117+
@Incubating
118+
String GETTER_PROPERTY_MATCHER_CLASSNAME = "hibernate.validator.getter_property_matcher";
119+
110120
/**
111121
* <p>
112122
* Returns the {@link ResourceBundleLocator} used by the
@@ -311,4 +321,16 @@ public interface HibernateValidatorConfiguration extends Configuration<Hibernate
311321
*/
312322
@Incubating
313323
HibernateValidatorConfiguration constraintValidatorPayload(Object constraintValidatorPayload);
324+
325+
/**
326+
* Allows to set a getter property matcher which defines rules of what a JavaBean getter is.
327+
*
328+
* @param getterPropertyMatcher the {@link GetterPropertyMatcher} to be used
329+
*
330+
* @return {@code this} following the chaining method pattern
331+
*
332+
* @since 6.1.0
333+
*/
334+
@Incubating
335+
HibernateValidatorConfiguration getterPropertyMatcher(GetterPropertyMatcher getterPropertyMatcher);
314336
}

engine/src/main/java/org/hibernate/validator/HibernateValidatorFactory.java

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import org.hibernate.validator.constraints.ParameterScriptAssert;
1515
import org.hibernate.validator.constraints.ScriptAssert;
16+
import org.hibernate.validator.spi.properties.GetterPropertyMatcher;
1617
import org.hibernate.validator.spi.scripting.ScriptEvaluator;
1718
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
1819

@@ -47,6 +48,16 @@ public interface HibernateValidatorFactory extends ValidatorFactory {
4748
@Incubating
4849
Duration getTemporalValidationTolerance();
4950

51+
/**
52+
* Returns the getter property matcher which defines what rules of what a JavaBeans getter is.
53+
*
54+
* @return the getter property matcher of current {@link ValidatorFactory}
55+
*
56+
* @since 6.1.0
57+
*/
58+
@Incubating
59+
GetterPropertyMatcher getGetterPropertyMatcher();
60+
5061
/**
5162
* Returns a context for validator configuration via options from the
5263
* Bean Validation API as well as specific ones from Hibernate Validator.

engine/src/main/java/org/hibernate/validator/internal/cfg/context/DefaultConstraintMapping.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl;
2525
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
2626
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
27-
import org.hibernate.validator.internal.properties.DefaultGetterPropertyMatcher;
2827
import org.hibernate.validator.internal.util.Contracts;
2928
import org.hibernate.validator.internal.util.TypeResolutionHelper;
3029
import org.hibernate.validator.internal.util.logging.Log;
3130
import org.hibernate.validator.internal.util.logging.LoggerFactory;
31+
import org.hibernate.validator.spi.properties.GetterPropertyMatcher;
3232

3333
/**
3434
* Default implementation of {@link ConstraintMapping}.
@@ -41,13 +41,15 @@ public class DefaultConstraintMapping implements ConstraintMapping {
4141

4242
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
4343

44+
private final GetterPropertyMatcher getterPropertyMatcher;
4445
private final AnnotationProcessingOptionsImpl annotationProcessingOptions;
4546
private final Set<Class<?>> configuredTypes;
4647
private final Set<TypeConstraintMappingContextImpl<?>> typeContexts;
4748
private final Set<Class<?>> definedConstraints;
4849
private final Set<ConstraintDefinitionContextImpl<?>> constraintContexts;
4950

50-
public DefaultConstraintMapping() {
51+
public DefaultConstraintMapping(GetterPropertyMatcher getterPropertyMatcher) {
52+
this.getterPropertyMatcher = getterPropertyMatcher;
5153
this.annotationProcessingOptions = new AnnotationProcessingOptionsImpl();
5254
this.configuredTypes = newHashSet();
5355
this.typeContexts = newHashSet();
@@ -63,7 +65,7 @@ public final <C> TypeConstraintMappingContext<C> type(Class<C> type) {
6365
throw LOG.getBeanClassHasAlreadyBeConfiguredViaProgrammaticApiException( type );
6466
}
6567

66-
TypeConstraintMappingContextImpl<C> typeContext = new TypeConstraintMappingContextImpl<>( this, type, new DefaultGetterPropertyMatcher() );
68+
TypeConstraintMappingContextImpl<C> typeContext = new TypeConstraintMappingContextImpl<>( this, type, getterPropertyMatcher );
6769
typeContexts.add( typeContext );
6870
configuredTypes.add( type );
6971

engine/src/main/java/org/hibernate/validator/internal/engine/ConfigurationImpl.java

+26-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.hibernate.validator.internal.engine.resolver.TraversableResolvers;
4343
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
4444
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
45+
import org.hibernate.validator.internal.properties.DefaultGetterPropertyMatcher;
4546
import org.hibernate.validator.internal.util.Contracts;
4647
import org.hibernate.validator.internal.util.Version;
4748
import org.hibernate.validator.internal.util.logging.Log;
@@ -53,6 +54,7 @@
5354
import org.hibernate.validator.internal.xml.config.ValidationXmlParser;
5455
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
5556
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
57+
import org.hibernate.validator.spi.properties.GetterPropertyMatcher;
5658
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
5759
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
5860

@@ -103,6 +105,7 @@ public class ConfigurationImpl implements HibernateValidatorConfiguration, Confi
103105
private ScriptEvaluatorFactory scriptEvaluatorFactory;
104106
private Duration temporalValidationTolerance;
105107
private Object constraintValidatorPayload;
108+
private GetterPropertyMatcher getterPropertyMatcher;
106109

107110
public ConfigurationImpl(BootstrapState state) {
108111
this();
@@ -294,6 +297,14 @@ public HibernateValidatorConfiguration constraintValidatorPayload(Object constra
294297
return this;
295298
}
296299

300+
@Override
301+
public HibernateValidatorConfiguration getterPropertyMatcher(GetterPropertyMatcher getterPropertyMatcher) {
302+
Contracts.assertNotNull( getterPropertyMatcher, MESSAGES.parameterMustNotBeNull( "getterPropertyMatcher" ) );
303+
304+
this.getterPropertyMatcher = getterPropertyMatcher;
305+
return this;
306+
}
307+
297308
public boolean isAllowParallelMethodsDefineParameterConstraints() {
298309
return this.methodValidationConfigurationBuilder.isAllowParallelMethodsDefineParameterConstraints();
299310
}
@@ -304,7 +315,17 @@ public MethodValidationConfiguration getMethodValidationConfiguration() {
304315

305316
@Override
306317
public final DefaultConstraintMapping createConstraintMapping() {
307-
return new DefaultConstraintMapping();
318+
GetterPropertyMatcher getterPropertyMatcherToUse = null;
319+
if ( getterPropertyMatcher == null ) {
320+
getterPropertyMatcherToUse = new DefaultGetterPropertyMatcher();
321+
LOG.creatingConstraintMappingPriorToBuildingFactoryWithoutDefinedFilter();
322+
}
323+
else {
324+
getterPropertyMatcherToUse = getterPropertyMatcher;
325+
}
326+
LOG.creatingConstraintMappingPriorToBuildingFactory( getterPropertyMatcherToUse.getClass() );
327+
328+
return new DefaultConstraintMapping( getterPropertyMatcherToUse );
308329
}
309330

310331
@Override
@@ -450,6 +471,10 @@ public Object getConstraintValidatorPayload() {
450471
return constraintValidatorPayload;
451472
}
452473

474+
public GetterPropertyMatcher getGetterPropertyMatcher() {
475+
return getterPropertyMatcher;
476+
}
477+
453478
@Override
454479
public Set<ValueExtractor<?>> getValueExtractors() {
455480
return validationBootstrapParameters.getValueExtractorDescriptors()

engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorFactoryImpl.java

+43-9
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
142142
ClassLoader externalClassLoader = getExternalClassLoader( configurationState );
143143

144144
this.valueExtractorManager = new ValueExtractorManager( configurationState.getValueExtractors() );
145-
this.getterPropertyMatcher = new DefaultGetterPropertyMatcher();
146145
this.beanMetaDataManagers = new ConcurrentHashMap<>();
147146
this.constraintHelper = new ConstraintHelper();
148147
this.typeResolutionHelper = new TypeResolutionHelper();
@@ -152,6 +151,9 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
152151
if ( configurationState instanceof ConfigurationImpl ) {
153152
hibernateSpecificConfig = (ConfigurationImpl) configurationState;
154153
}
154+
Map<String, String> properties = configurationState.getProperties();
155+
156+
this.getterPropertyMatcher = getGetterPropertyMatcher( hibernateSpecificConfig, properties, externalClassLoader );
155157

156158
// HV-302; don't load XmlMappingParser if not necessary
157159
if ( configurationState.getMappingStreams().isEmpty() ) {
@@ -167,14 +169,13 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
167169
getConstraintMappings(
168170
typeResolutionHelper,
169171
configurationState,
172+
getterPropertyMatcher,
170173
externalClassLoader
171174
)
172175
);
173176

174177
registerCustomConstraintValidators( constraintMappings, constraintHelper );
175178

176-
Map<String, String> properties = configurationState.getProperties();
177-
178179
this.methodValidationConfiguration = new MethodValidationConfiguration.Builder()
179180
.allowOverridingMethodAlterParameterConstraint(
180181
getAllowOverridingMethodAlterParameterConstraint( hibernateSpecificConfig, properties )
@@ -213,7 +214,7 @@ private static ClassLoader getExternalClassLoader(ConfigurationState configurati
213214
}
214215

215216
private static Set<DefaultConstraintMapping> getConstraintMappings(TypeResolutionHelper typeResolutionHelper,
216-
ConfigurationState configurationState, ClassLoader externalClassLoader) {
217+
ConfigurationState configurationState, GetterPropertyMatcher getterPropertyMatcher, ClassLoader externalClassLoader) {
217218
Set<DefaultConstraintMapping> constraintMappings = newHashSet();
218219

219220
if ( configurationState instanceof ConfigurationImpl ) {
@@ -229,7 +230,7 @@ private static Set<DefaultConstraintMapping> getConstraintMappings(TypeResolutio
229230
ConstraintMappingContributor serviceLoaderBasedContributor = new ServiceLoaderBasedConstraintMappingContributor(
230231
typeResolutionHelper,
231232
externalClassLoader != null ? externalClassLoader : run( GetClassLoader.fromContext() ) );
232-
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( constraintMappings );
233+
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( getterPropertyMatcher, constraintMappings );
233234
serviceLoaderBasedContributor.createConstraintMappings( builder );
234235
}
235236

@@ -238,7 +239,7 @@ private static Set<DefaultConstraintMapping> getConstraintMappings(TypeResolutio
238239
externalClassLoader );
239240

240241
for ( ConstraintMappingContributor contributor : contributors ) {
241-
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( constraintMappings );
242+
DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( getterPropertyMatcher, constraintMappings );
242243
contributor.createConstraintMappings( builder );
243244
}
244245

@@ -294,6 +295,11 @@ public Duration getTemporalValidationTolerance() {
294295
return validatorFactoryScopedContext.getTemporalValidationTolerance();
295296
}
296297

298+
@Override
299+
public GetterPropertyMatcher getGetterPropertyMatcher() {
300+
return getterPropertyMatcher;
301+
}
302+
297303
public boolean isFailFast() {
298304
return validatorFactoryScopedContext.isFailFast();
299305
}
@@ -555,6 +561,32 @@ private Object getConstraintValidatorPayload(ConfigurationState configurationSta
555561
return null;
556562
}
557563

564+
private static GetterPropertyMatcher getGetterPropertyMatcher(ConfigurationImpl hibernateSpecificConfig, Map<String, String> properties, ClassLoader externalClassLoader) {
565+
if ( hibernateSpecificConfig.getGetterPropertyMatcher() != null ) {
566+
LOG.usingGetterPropertyMatcher( hibernateSpecificConfig.getGetterPropertyMatcher().getClass() );
567+
return hibernateSpecificConfig.getGetterPropertyMatcher();
568+
}
569+
570+
String getterPropertyMatcherFqcn = properties.get( HibernateValidatorConfiguration.GETTER_PROPERTY_MATCHER_CLASSNAME );
571+
if ( getterPropertyMatcherFqcn != null ) {
572+
try {
573+
@SuppressWarnings("unchecked")
574+
Class<? extends GetterPropertyMatcher> clazz = (Class<? extends GetterPropertyMatcher>) run(
575+
LoadClass.action( getterPropertyMatcherFqcn, externalClassLoader )
576+
);
577+
GetterPropertyMatcher getterPropertyMatcher = run( NewInstance.action( clazz, "getter property matcher class" ) );
578+
LOG.usingGetterPropertyMatcher( clazz );
579+
580+
return getterPropertyMatcher;
581+
}
582+
catch (Exception e) {
583+
throw LOG.getUnableToInstantiateGetterPropertyMatcherClassException( getterPropertyMatcherFqcn, e );
584+
}
585+
}
586+
587+
return new DefaultGetterPropertyMatcher();
588+
}
589+
558590
private static void registerCustomConstraintValidators(Set<DefaultConstraintMapping> constraintMappings,
559591
ConstraintHelper constraintHelper) {
560592
Set<Class<?>> definedConstraints = newHashSet();
@@ -603,16 +635,18 @@ private static <T> T run(PrivilegedAction<T> action) {
603635
*/
604636
private static class DefaultConstraintMappingBuilder
605637
implements ConstraintMappingContributor.ConstraintMappingBuilder {
638+
639+
private final GetterPropertyMatcher getterPropertyMatcher;
606640
private final Set<DefaultConstraintMapping> mappings;
607641

608-
public DefaultConstraintMappingBuilder(Set<DefaultConstraintMapping> mappings) {
609-
super();
642+
public DefaultConstraintMappingBuilder(GetterPropertyMatcher getterPropertyMatcher, Set<DefaultConstraintMapping> mappings) {
643+
this.getterPropertyMatcher = getterPropertyMatcher;
610644
this.mappings = mappings;
611645
}
612646

613647
@Override
614648
public ConstraintMapping addConstraintMapping() {
615-
DefaultConstraintMapping mapping = new DefaultConstraintMapping();
649+
DefaultConstraintMapping mapping = new DefaultConstraintMapping( getterPropertyMatcher );
616650
mappings.add( mapping );
617651
return mapping;
618652
}

engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ ConstraintDefinitionException getConstraintValidatorDefinitionConstraintMismatch
871871
void creatingConstraintMappingPriorToBuildingFactory(@FormatWith(ClassObjectFormatter.class) Class<? extends GetterPropertyMatcher> getterPropertyMatcherClass);
872872

873873
@LogMessage(level = WARN)
874-
@Message(id = 247, value = "As no property filter was defined for current configuration a default one will be used.")
874+
@Message(id = 247, value = "As no getter property matcher was defined for current configuration a default one will be used.")
875875
void creatingConstraintMappingPriorToBuildingFactoryWithoutDefinedFilter();
876876

877877
@Message(id = 248, value = "Unable to access field %3$s of class %2$s using lookup %1$s.")

engine/src/test/java/org/hibernate/validator/test/internal/metadata/core/MetaConstraintTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ public void setUp() throws Exception {
5050
@Test
5151
@TestForIssue(jiraKey = "HV-930")
5252
public void two_meta_constraints_for_the_same_constraint_should_be_equal() throws Exception {
53-
DefaultGetterPropertyMatcher propertyFilter = new DefaultGetterPropertyMatcher();
53+
DefaultGetterPropertyMatcher getterPropertyMatcher = new DefaultGetterPropertyMatcher();
5454
ConstraintDescriptorImpl<NotNull> constraintDescriptor1 = new ConstraintDescriptorImpl<>(
55-
constraintHelper, JavaBean.toJavaBeanExecutable( propertyFilter, barMethod ), constraintAnnotationDescriptor, METHOD
55+
constraintHelper, JavaBean.toJavaBeanExecutable( getterPropertyMatcher, barMethod ), constraintAnnotationDescriptor, METHOD
5656
);
5757
ConstraintLocation location1 = ConstraintLocation.forClass( Foo.class );
5858
MetaConstraint<NotNull> metaConstraint1 = MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor1, location1 );
5959

6060
ConstraintDescriptorImpl<NotNull> constraintDescriptor2 = new ConstraintDescriptorImpl<>(
61-
constraintHelper, JavaBean.toJavaBeanExecutable( propertyFilter, barMethod ), constraintAnnotationDescriptor, METHOD
61+
constraintHelper, JavaBean.toJavaBeanExecutable( getterPropertyMatcher, barMethod ), constraintAnnotationDescriptor, METHOD
6262
);
6363
ConstraintLocation location2 = ConstraintLocation.forClass( Foo.class );
6464
MetaConstraint<NotNull> metaConstraint2 = MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor2, location2 );

0 commit comments

Comments
 (0)