Skip to content

Commit e34276b

Browse files
marko-bekhtagsmet
authored andcommitted
HV-1363 Moved getter detection logic to separate class
1 parent dd51f80 commit e34276b

32 files changed

+298
-120
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
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;
2728
import org.hibernate.validator.internal.util.Contracts;
2829
import org.hibernate.validator.internal.util.TypeResolutionHelper;
2930
import org.hibernate.validator.internal.util.logging.Log;
@@ -62,7 +63,7 @@ public final <C> TypeConstraintMappingContext<C> type(Class<C> type) {
6263
throw LOG.getBeanClassHasAlreadyBeConfiguredViaProgrammaticApiException( type );
6364
}
6465

65-
TypeConstraintMappingContextImpl<C> typeContext = new TypeConstraintMappingContextImpl<>( this, type );
66+
TypeConstraintMappingContextImpl<C> typeContext = new TypeConstraintMappingContextImpl<>( this, type, new DefaultGetterPropertyMatcher() );
6667
typeContexts.add( typeContext );
6768
configuredTypes.add( type );
6869

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

+11-15
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,17 @@
3737
import org.hibernate.validator.internal.properties.Property;
3838
import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable;
3939
import org.hibernate.validator.internal.properties.javabean.JavaBeanField;
40-
import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter;
4140
import org.hibernate.validator.internal.util.Contracts;
4241
import org.hibernate.validator.internal.util.ExecutableHelper;
43-
import org.hibernate.validator.internal.util.ReflectionHelper;
4442
import org.hibernate.validator.internal.util.TypeResolutionHelper;
4543
import org.hibernate.validator.internal.util.logging.Log;
4644
import org.hibernate.validator.internal.util.logging.LoggerFactory;
4745
import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredConstructor;
4846
import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField;
4947
import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod;
50-
import org.hibernate.validator.internal.util.privilegedactions.GetMethod;
48+
import org.hibernate.validator.internal.util.privilegedactions.GetMethodFromPropertyName;
5149
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;
50+
import org.hibernate.validator.properties.GetterPropertyMatcher;
5251
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
5352

5453
/**
@@ -74,9 +73,12 @@ public final class TypeConstraintMappingContextImpl<C> extends ConstraintMapping
7473
private List<Class<?>> defaultGroupSequence;
7574
private Class<? extends DefaultGroupSequenceProvider<? super C>> defaultGroupSequenceProviderClass;
7675

77-
TypeConstraintMappingContextImpl(DefaultConstraintMapping mapping, Class<C> beanClass) {
76+
private final GetterPropertyMatcher getterPropertyMatcher;
77+
78+
TypeConstraintMappingContextImpl(DefaultConstraintMapping mapping, Class<C> beanClass, GetterPropertyMatcher getterPropertyMatcher) {
7879
super( mapping );
7980
this.beanClass = beanClass;
81+
this.getterPropertyMatcher = getterPropertyMatcher;
8082
mapping.getAnnotationProcessingOptions().ignoreAnnotationConstraintForClass( beanClass, Boolean.FALSE );
8183
}
8284

@@ -153,7 +155,7 @@ public MethodConstraintMappingContext method(String name, Class<?>... parameterT
153155
throw LOG.getBeanDoesNotContainMethodException( beanClass, name, parameterTypes );
154156
}
155157

156-
Callable callable = JavaBeanExecutable.of( method );
158+
Callable callable = JavaBeanExecutable.of( getterPropertyMatcher, method );
157159

158160
if ( configuredMembers.contains( callable ) ) {
159161
throw LOG.getMethodHasAlreadyBeenConfiguredViaProgrammaticApiException(
@@ -180,7 +182,7 @@ public ConstructorConstraintMappingContext constructor(Class<?>... parameterType
180182
);
181183
}
182184

183-
Callable callable = JavaBeanExecutable.of( constructor );
185+
Callable callable = JavaBeanExecutable.of( getterPropertyMatcher, constructor );
184186

185187
if ( configuredMembers.contains( callable ) ) {
186188
throw LOG.getConstructorHasAlreadyBeConfiguredViaProgrammaticApiException(
@@ -279,15 +281,9 @@ private Property getProperty(Class<?> clazz, String property, ElementType elemen
279281
return field == null ? null : new JavaBeanField( field );
280282
}
281283
else {
282-
Method method = null;
283-
String methodName = property.substring( 0, 1 ).toUpperCase() + property.substring( 1 );
284-
for ( String prefix : ReflectionHelper.PROPERTY_ACCESSOR_PREFIXES ) {
285-
method = run( GetMethod.action( clazz, prefix + methodName ) );
286-
if ( method != null ) {
287-
break;
288-
}
289-
}
290-
return method == null ? null : new JavaBeanGetter( method );
284+
Method method = GetMethodFromPropertyName.action( clazz, getterPropertyMatcher, property ).run();
285+
286+
return method == null ? null : JavaBeanExecutable.of( getterPropertyMatcher, method ).as( Property.class );
291287
}
292288
}
293289

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.hibernate.validator.internal.metadata.provider.MetaDataProvider;
4848
import org.hibernate.validator.internal.metadata.provider.ProgrammaticMetaDataProvider;
4949
import org.hibernate.validator.internal.metadata.provider.XmlMetaDataProvider;
50+
import org.hibernate.validator.internal.properties.DefaultGetterPropertyMatcher;
5051
import org.hibernate.validator.internal.util.Contracts;
5152
import org.hibernate.validator.internal.util.ExecutableHelper;
5253
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
@@ -59,6 +60,7 @@
5960
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;
6061
import org.hibernate.validator.internal.util.stereotypes.Immutable;
6162
import org.hibernate.validator.internal.util.stereotypes.ThreadSafe;
63+
import org.hibernate.validator.properties.GetterPropertyMatcher;
6264
import org.hibernate.validator.spi.cfg.ConstraintMappingContributor;
6365
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
6466

@@ -132,12 +134,15 @@ public class ValidatorFactoryImpl implements HibernateValidatorFactory {
132134

133135
private final ValueExtractorManager valueExtractorManager;
134136

137+
private final GetterPropertyMatcher getterPropertyMatcher;
138+
135139
private final ValidationOrderGenerator validationOrderGenerator;
136140

137141
public ValidatorFactoryImpl(ConfigurationState configurationState) {
138142
ClassLoader externalClassLoader = getExternalClassLoader( configurationState );
139143

140144
this.valueExtractorManager = new ValueExtractorManager( configurationState.getValueExtractors() );
145+
this.getterPropertyMatcher = new DefaultGetterPropertyMatcher();
141146
this.beanMetaDataManagers = new ConcurrentHashMap<>();
142147
this.constraintHelper = new ConstraintHelper();
143148
this.typeResolutionHelper = new TypeResolutionHelper();
@@ -154,7 +159,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
154159
}
155160
else {
156161
this.xmlMetaDataProvider = new XmlMetaDataProvider(
157-
constraintHelper, typeResolutionHelper, valueExtractorManager, configurationState.getMappingStreams(), externalClassLoader
162+
constraintHelper, typeResolutionHelper, valueExtractorManager, getterPropertyMatcher, configurationState.getMappingStreams(), externalClassLoader
158163
);
159164
}
160165

@@ -347,11 +352,12 @@ Validator createValidator(ConstraintValidatorFactory constraintValidatorFactory,
347352
typeResolutionHelper,
348353
validatorFactoryScopedContext.getParameterNameProvider(),
349354
valueExtractorManager,
355+
getterPropertyMatcher,
350356
validationOrderGenerator,
351357
buildDataProviders(),
352358
methodValidationConfiguration
353359
)
354-
);
360+
);
355361

356362
return new ValidatorImpl(
357363
constraintValidatorFactory,

engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.hibernate.validator.internal.util.TypeResolutionHelper;
3838
import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
3939
import org.hibernate.validator.internal.util.stereotypes.Immutable;
40+
import org.hibernate.validator.properties.GetterPropertyMatcher;
4041

4142
/**
4243
* This manager is in charge of providing all constraint related meta data
@@ -121,6 +122,7 @@ public BeanMetaDataManager(ConstraintHelper constraintHelper,
121122
TypeResolutionHelper typeResolutionHelper,
122123
ExecutableParameterNameProvider parameterNameProvider,
123124
ValueExtractorManager valueExtractorManager,
125+
GetterPropertyMatcher getterPropertyMatcher,
124126
ValidationOrderGenerator validationOrderGenerator,
125127
List<MetaDataProvider> optionalMetaDataProviders,
126128
MethodValidationConfiguration methodValidationConfiguration) {
@@ -147,6 +149,7 @@ public BeanMetaDataManager(ConstraintHelper constraintHelper,
147149
constraintHelper,
148150
typeResolutionHelper,
149151
valueExtractorManager,
152+
getterPropertyMatcher,
150153
annotationProcessingOptions
151154
);
152155
List<MetaDataProvider> tmpMetaDataProviders = new ArrayList<>( optionalMetaDataProviders.size() + 1 );

engine/src/main/java/org/hibernate/validator/internal/metadata/provider/AnnotationMetaDataProvider.java

+14-10
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethods;
8080
import org.hibernate.validator.internal.util.privilegedactions.GetMethods;
8181
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;
82+
import org.hibernate.validator.properties.GetterPropertyMatcher;
8283
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
8384

8485
/**
@@ -98,16 +99,19 @@ public class AnnotationMetaDataProvider implements MetaDataProvider {
9899
private final TypeResolutionHelper typeResolutionHelper;
99100
private final AnnotationProcessingOptions annotationProcessingOptions;
100101
private final ValueExtractorManager valueExtractorManager;
102+
private final GetterPropertyMatcher getterPropertyMatcher;
101103

102104
private final BeanConfiguration<Object> objectBeanConfiguration;
103105

104106
public AnnotationMetaDataProvider(ConstraintHelper constraintHelper,
105107
TypeResolutionHelper typeResolutionHelper,
106108
ValueExtractorManager valueExtractorManager,
109+
GetterPropertyMatcher getterPropertyMatcher,
107110
AnnotationProcessingOptions annotationProcessingOptions) {
108111
this.constraintHelper = constraintHelper;
109112
this.typeResolutionHelper = typeResolutionHelper;
110113
this.valueExtractorManager = valueExtractorManager;
114+
this.getterPropertyMatcher = getterPropertyMatcher;
111115
this.annotationProcessingOptions = annotationProcessingOptions;
112116

113117
this.objectBeanConfiguration = retrieveBeanConfiguration( Object.class );
@@ -302,7 +306,7 @@ private Set<ConstrainedExecutable> getMetaData(Executable[] executableElements)
302306
* given element.
303307
*/
304308
private ConstrainedExecutable findExecutableMetaData(Executable executable) {
305-
Callable callable = JavaBeanExecutable.of( executable );
309+
Callable callable = JavaBeanExecutable.of( getterPropertyMatcher, executable );
306310
List<ConstrainedParameter> parameterConstraints = getParameterMetaData( executable, callable );
307311

308312
Map<ConstraintType, List<ConstraintDescriptorImpl<?>>> executableConstraints = findConstraints(
@@ -797,7 +801,7 @@ private Set<MetaConstraint<?>> findTypeUseConstraints(Constrainable constrainabl
797801
*/
798802
private <A extends Annotation> MetaConstraint<?> createTypeArgumentMetaConstraint(ConstraintDescriptorImpl<A> descriptor, TypeArgumentLocation location,
799803
TypeVariable<?> typeVariable, Type type) {
800-
ConstraintLocation constraintLocation = ConstraintLocation.forTypeArgument( location.toConstraintLocation(), typeVariable, type );
804+
ConstraintLocation constraintLocation = ConstraintLocation.forTypeArgument( location.toConstraintLocation( getterPropertyMatcher ), typeVariable, type );
801805
return MetaConstraints.create( typeResolutionHelper, valueExtractorManager, descriptor, constraintLocation );
802806
}
803807

@@ -815,7 +819,7 @@ private CascadingMetaDataBuilder getCascadingMetaData(Type type, AnnotatedElemen
815819
* which might not be possible (for instance for {@code java.util} classes).
816820
*/
817821
private interface TypeArgumentLocation {
818-
ConstraintLocation toConstraintLocation();
822+
ConstraintLocation toConstraintLocation(GetterPropertyMatcher getterPropertyMatcher);
819823
}
820824

821825
private static class TypeArgumentExecutableParameterLocation implements TypeArgumentLocation {
@@ -829,8 +833,8 @@ private TypeArgumentExecutableParameterLocation(Executable executable, int index
829833
}
830834

831835
@Override
832-
public ConstraintLocation toConstraintLocation() {
833-
return ConstraintLocation.forParameter( JavaBeanExecutable.of( executable ), index );
836+
public ConstraintLocation toConstraintLocation(GetterPropertyMatcher getterPropertyMatcher) {
837+
return ConstraintLocation.forParameter( JavaBeanExecutable.of( getterPropertyMatcher, executable ), index );
834838
}
835839
}
836840

@@ -842,7 +846,7 @@ private TypeArgumentFieldLocation(Field field) {
842846
}
843847

844848
@Override
845-
public ConstraintLocation toConstraintLocation() {
849+
public ConstraintLocation toConstraintLocation(GetterPropertyMatcher getterPropertyMatcher) {
846850
return ConstraintLocation.forProperty( new JavaBeanField( field ) );
847851
}
848852
}
@@ -855,8 +859,8 @@ private TypeArgumentReturnValueLocation(Executable executable) {
855859
}
856860

857861
@Override
858-
public ConstraintLocation toConstraintLocation() {
859-
return ConstraintLocation.forReturnValue( JavaBeanExecutable.of( executable ) );
862+
public ConstraintLocation toConstraintLocation(GetterPropertyMatcher getterPropertyMatcher) {
863+
return ConstraintLocation.forReturnValue( JavaBeanExecutable.of( getterPropertyMatcher, executable ) );
860864
}
861865
}
862866

@@ -872,8 +876,8 @@ private NestedTypeArgumentLocation(TypeArgumentLocation parentLocation, TypeVari
872876
}
873877

874878
@Override
875-
public ConstraintLocation toConstraintLocation() {
876-
return ConstraintLocation.forTypeArgument( parentLocation.toConstraintLocation(), typeParameter, typeOfAnnotatedElement );
879+
public ConstraintLocation toConstraintLocation(GetterPropertyMatcher getterPropertyMatcher) {
880+
return ConstraintLocation.forTypeArgument( parentLocation.toConstraintLocation( getterPropertyMatcher ), typeParameter, typeOfAnnotatedElement );
877881
}
878882

879883
}

engine/src/main/java/org/hibernate/validator/internal/metadata/provider/XmlMetaDataProvider.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.hibernate.validator.internal.util.TypeResolutionHelper;
2222
import org.hibernate.validator.internal.util.stereotypes.Immutable;
2323
import org.hibernate.validator.internal.xml.mapping.MappingXmlParser;
24+
import org.hibernate.validator.properties.GetterPropertyMatcher;
2425

2526
/**
2627
* A {@link MetaDataProvider} providing constraint related meta data based on
@@ -40,11 +41,12 @@ public class XmlMetaDataProvider implements MetaDataProvider {
4041
public XmlMetaDataProvider(ConstraintHelper constraintHelper,
4142
TypeResolutionHelper typeResolutionHelper,
4243
ValueExtractorManager valueExtractorManager,
44+
GetterPropertyMatcher getterPropertyMatcher,
4345
Set<InputStream> mappingStreams,
4446
ClassLoader externalClassLoader) {
4547

4648
MappingXmlParser mappingParser = new MappingXmlParser( constraintHelper, typeResolutionHelper, valueExtractorManager,
47-
externalClassLoader );
49+
getterPropertyMatcher, externalClassLoader );
4850
mappingParser.parse( mappingStreams );
4951

5052
configuredBeans = CollectionHelper.toImmutableMap( createBeanConfigurations( mappingParser ) );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Hibernate Validator, declare and validate application constraints
3+
*
4+
* License: Apache License, Version 2.0
5+
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6+
*/
7+
package org.hibernate.validator.internal.properties;
8+
9+
import java.lang.reflect.Constructor;
10+
import java.lang.reflect.Executable;
11+
import java.lang.reflect.Method;
12+
import java.util.Arrays;
13+
import java.util.Set;
14+
import java.util.stream.Collectors;
15+
16+
import org.hibernate.validator.internal.util.StringHelper;
17+
import org.hibernate.validator.properties.GetterPropertyMatcher;
18+
19+
/**
20+
* @author Marko Bekhta
21+
*/
22+
public class DefaultGetterPropertyMatcher implements GetterPropertyMatcher {
23+
24+
private static final String PROPERTY_ACCESSOR_PREFIX_GET = "get";
25+
private static final String PROPERTY_ACCESSOR_PREFIX_IS = "is";
26+
private static final String PROPERTY_ACCESSOR_PREFIX_HAS = "has";
27+
public static final String[] PROPERTY_ACCESSOR_PREFIXES = {
28+
PROPERTY_ACCESSOR_PREFIX_GET,
29+
PROPERTY_ACCESSOR_PREFIX_IS,
30+
PROPERTY_ACCESSOR_PREFIX_HAS
31+
};
32+
33+
/**
34+
* Checks whether the given executable is a valid JavaBean getter method, which
35+
* is the case if
36+
* <ul>
37+
* <li>its name starts with "get" and it has a return type but no parameter or</li>
38+
* <li>its name starts with "is", it has no parameter and is returning
39+
* {@code boolean} or</li>
40+
* <li>its name starts with "has", it has no parameter and is returning
41+
* {@code boolean} (HV-specific, not mandated by JavaBeans spec).</li>
42+
* </ul>
43+
*
44+
* @param executable The executable of interest.
45+
*
46+
* @return {@code true}, if the given executable is a JavaBean getter method,
47+
* {@code false} otherwise.
48+
*/
49+
@Override
50+
public boolean isProperty(Executable executable) {
51+
if ( executable instanceof Constructor ) {
52+
return false;
53+
}
54+
if ( executable.getParameterTypes().length != 0 ) {
55+
return false;
56+
}
57+
Method method = (Method) executable;
58+
59+
String methodName = method.getName();
60+
61+
//<PropertyType> get<PropertyName>()
62+
if ( methodName.startsWith( PROPERTY_ACCESSOR_PREFIX_GET ) && method.getReturnType() != void.class ) {
63+
return true;
64+
}
65+
//boolean is<PropertyName>()
66+
else if ( methodName.startsWith( PROPERTY_ACCESSOR_PREFIX_IS ) && method.getReturnType() == boolean.class ) {
67+
return true;
68+
}
69+
//boolean has<PropertyName>()
70+
else if ( methodName.startsWith( PROPERTY_ACCESSOR_PREFIX_HAS ) && method.getReturnType() == boolean.class ) {
71+
return true;
72+
}
73+
74+
return false;
75+
}
76+
77+
@Override
78+
public String getPropertyName(Method method) {
79+
String name = null;
80+
String methodName = method.getName();
81+
for ( String prefix : PROPERTY_ACCESSOR_PREFIXES ) {
82+
if ( methodName.startsWith( prefix ) ) {
83+
name = StringHelper.decapitalize( methodName.substring( prefix.length() ) );
84+
}
85+
}
86+
return name;
87+
}
88+
89+
@Override
90+
public Set<String> getPossibleMethodNamesForProperty(String propertyName) {
91+
char[] chars = propertyName.toCharArray();
92+
chars[0] = Character.toUpperCase( chars[0] );
93+
String propertyMethodEnding = new String( chars );
94+
return Arrays.stream( PROPERTY_ACCESSOR_PREFIXES )
95+
.map( prefix -> prefix + propertyMethodEnding )
96+
.collect( Collectors.toSet() );
97+
}
98+
}

0 commit comments

Comments
 (0)