diff --git a/engine/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java b/engine/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java index 45773d3949..09fe5f496d 100644 --- a/engine/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java +++ b/engine/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java @@ -6,6 +6,7 @@ */ package org.hibernate.validator; +import java.lang.invoke.MethodHandles.Lookup; import java.time.Duration; import java.util.Set; @@ -311,4 +312,37 @@ public interface HibernateValidatorConfiguration extends Configuration> typeContexts; private final Set> definedConstraints; private final Set> constraintContexts; + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; - public DefaultConstraintMapping() { + public DefaultConstraintMapping(JavaBeanPropertyAccessorFactory propertyAccessorFactory) { this.annotationProcessingOptions = new AnnotationProcessingOptionsImpl(); this.configuredTypes = newHashSet(); this.typeContexts = newHashSet(); this.definedConstraints = newHashSet(); this.constraintContexts = newHashSet(); + this.propertyAccessorFactory = propertyAccessorFactory; } @Override @@ -124,4 +127,8 @@ public Set> getConstraintDefinitionContribut return contributions; } + + JavaBeanPropertyAccessorFactory getPropertyAccessorFactory() { + return propertyAccessorFactory; + } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/TypeConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/TypeConstraintMappingContextImpl.java index 9e41540308..ef577b5fc4 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/TypeConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/TypeConstraintMappingContextImpl.java @@ -184,7 +184,7 @@ public MethodConstraintMappingContext method(String name, Class... parameterT throw LOG.getBeanDoesNotContainMethodException( beanClass, name, parameterTypes ); } - JavaBeanMethod javaBeanMethod = JavaBeanExecutable.of( method ); + JavaBeanMethod javaBeanMethod = JavaBeanExecutable.of( mapping.getPropertyAccessorFactory(), method ); if ( configuredMembers.contains( javaBeanMethod ) ) { throw LOG.getMethodHasAlreadyBeenConfiguredViaProgrammaticApiException( @@ -289,7 +289,7 @@ private JavaBeanField getFieldProperty(Class clazz, String property) { Contracts.assertNotNull( clazz, MESSAGES.classCannotBeNull() ); Field field = run( GetDeclaredField.action( clazz, property ) ); - return field == null ? null : new JavaBeanField( field ); + return field == null ? null : new JavaBeanField( mapping.getPropertyAccessorFactory(), field ); } private JavaBeanGetter getGetterProperty(Class clazz, String property) { @@ -303,7 +303,7 @@ private JavaBeanGetter getGetterProperty(Class clazz, String property) { break; } } - return method == null ? null : new JavaBeanGetter( method ); + return method == null ? null : new JavaBeanGetter( mapping.getPropertyAccessorFactory(), method ); } /** diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/ConfigurationImpl.java b/engine/src/main/java/org/hibernate/validator/internal/engine/ConfigurationImpl.java index 863467d48a..be238ddb53 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/ConfigurationImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/ConfigurationImpl.java @@ -42,6 +42,7 @@ import org.hibernate.validator.internal.engine.resolver.TraversableResolvers; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.Contracts; import org.hibernate.validator.internal.util.Version; import org.hibernate.validator.internal.util.logging.Log; @@ -103,6 +104,8 @@ public class ConfigurationImpl implements HibernateValidatorConfiguration, Confi private ScriptEvaluatorFactory scriptEvaluatorFactory; private Duration temporalValidationTolerance; private Object constraintValidatorPayload; + private PropertyAccessKind propertyAccessKind; + private MethodHandles.Lookup lookup; public ConfigurationImpl(BootstrapState state) { this(); @@ -133,6 +136,10 @@ private ConfigurationImpl() { this.defaultConstraintValidatorFactory = new ConstraintValidatorFactoryImpl(); this.defaultParameterNameProvider = new DefaultParameterNameProvider(); this.defaultClockProvider = DefaultClockProvider.INSTANCE; + // we default to classical reflection access + this.propertyAccessKind = PropertyAccessKind.REFLECTION; + // set default lookup value to be used unless it will be redefined by users. + this.lookup = MethodHandles.lookup(); } @Override @@ -294,6 +301,22 @@ public HibernateValidatorConfiguration constraintValidatorPayload(Object constra return this; } + @Override + public HibernateValidatorConfiguration propertyAccessKind(PropertyAccessKind propertyAccessKind) { + Contracts.assertNotNull( propertyAccessKind, MESSAGES.parameterMustNotBeNull( "propertyAccessKind" ) ); + + this.propertyAccessKind = propertyAccessKind; + return this; + } + + @Override + public HibernateValidatorConfiguration externalLookup(MethodHandles.Lookup lookup) { + Contracts.assertNotNull( lookup, MESSAGES.parameterMustNotBeNull( "lookup" ) ); + + this.lookup = lookup; + return this; + } + public boolean isAllowParallelMethodsDefineParameterConstraints() { return this.methodValidationConfigurationBuilder.isAllowParallelMethodsDefineParameterConstraints(); } @@ -304,7 +327,7 @@ public MethodValidationConfiguration getMethodValidationConfiguration() { @Override public final DefaultConstraintMapping createConstraintMapping() { - return new DefaultConstraintMapping(); + return new DefaultConstraintMapping( JavaBeanPropertyAccessorFactory.of( this ) ); } @Override @@ -450,6 +473,14 @@ public Object getConstraintValidatorPayload() { return constraintValidatorPayload; } + public PropertyAccessKind getPropertyAccessKind() { + return propertyAccessKind; + } + + public MethodHandles.Lookup getLookup() { + return lookup; + } + @Override public Set> getValueExtractors() { return validationBootstrapParameters.getValueExtractorDescriptors() diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorFactoryImpl.java b/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorFactoryImpl.java index a112b42cab..d3bc994fbc 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorFactoryImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorFactoryImpl.java @@ -47,6 +47,7 @@ import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; import org.hibernate.validator.internal.metadata.provider.ProgrammaticMetaDataProvider; import org.hibernate.validator.internal.metadata.provider.XmlMetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.Contracts; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; @@ -134,6 +135,8 @@ public class ValidatorFactoryImpl implements HibernateValidatorFactory { private final ValidationOrderGenerator validationOrderGenerator; + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; + public ValidatorFactoryImpl(ConfigurationState configurationState) { ClassLoader externalClassLoader = getExternalClassLoader( configurationState ); @@ -147,6 +150,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) { if ( configurationState instanceof ConfigurationImpl ) { hibernateSpecificConfig = (ConfigurationImpl) configurationState; } + this.propertyAccessorFactory = JavaBeanPropertyAccessorFactory.of( hibernateSpecificConfig ); // HV-302; don't load XmlMappingParser if not necessary if ( configurationState.getMappingStreams().isEmpty() ) { @@ -154,12 +158,13 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) { } else { this.xmlMetaDataProvider = new XmlMetaDataProvider( - constraintHelper, typeResolutionHelper, valueExtractorManager, configurationState.getMappingStreams(), externalClassLoader + constraintHelper, typeResolutionHelper, valueExtractorManager, propertyAccessorFactory, configurationState.getMappingStreams(), externalClassLoader ); } this.constraintMappings = Collections.unmodifiableSet( getConstraintMappings( + propertyAccessorFactory, typeResolutionHelper, configurationState, externalClassLoader @@ -207,7 +212,7 @@ private static ClassLoader getExternalClassLoader(ConfigurationState configurati return ( configurationState instanceof ConfigurationImpl ) ? ( (ConfigurationImpl) configurationState ).getExternalClassLoader() : null; } - private static Set getConstraintMappings(TypeResolutionHelper typeResolutionHelper, + private static Set getConstraintMappings(JavaBeanPropertyAccessorFactory propertyAccessorFactory, TypeResolutionHelper typeResolutionHelper, ConfigurationState configurationState, ClassLoader externalClassLoader) { Set constraintMappings = newHashSet(); @@ -224,7 +229,7 @@ private static Set getConstraintMappings(TypeResolutio ConstraintMappingContributor serviceLoaderBasedContributor = new ServiceLoaderBasedConstraintMappingContributor( typeResolutionHelper, externalClassLoader != null ? externalClassLoader : run( GetClassLoader.fromContext() ) ); - DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( constraintMappings ); + DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( propertyAccessorFactory, constraintMappings ); serviceLoaderBasedContributor.createConstraintMappings( builder ); } @@ -233,7 +238,7 @@ private static Set getConstraintMappings(TypeResolutio externalClassLoader ); for ( ConstraintMappingContributor contributor : contributors ) { - DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( constraintMappings ); + DefaultConstraintMappingBuilder builder = new DefaultConstraintMappingBuilder( propertyAccessorFactory, constraintMappings ); contributor.createConstraintMappings( builder ); } @@ -349,7 +354,8 @@ Validator createValidator(ConstraintValidatorFactory constraintValidatorFactory, valueExtractorManager, validationOrderGenerator, buildDataProviders(), - methodValidationConfiguration + methodValidationConfiguration, + propertyAccessorFactory ) ); @@ -598,16 +604,18 @@ private static T run(PrivilegedAction action) { */ private static class DefaultConstraintMappingBuilder implements ConstraintMappingContributor.ConstraintMappingBuilder { + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; private final Set mappings; - public DefaultConstraintMappingBuilder(Set mappings) { + public DefaultConstraintMappingBuilder(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Set mappings) { super(); + this.propertyAccessorFactory = propertyAccessorFactory; this.mappings = mappings; } @Override public ConstraintMapping addConstraintMapping() { - DefaultConstraintMapping mapping = new DefaultConstraintMapping(); + DefaultConstraintMapping mapping = new DefaultConstraintMapping( propertyAccessorFactory ); mappings.add( mapping ); return mapping; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java index 197a3232c4..e9e6cdfc03 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/BeanMetaDataManager.java @@ -29,6 +29,7 @@ import org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; import org.hibernate.validator.internal.metadata.raw.BeanConfiguration; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.ConcurrentReferenceHashMap; import org.hibernate.validator.internal.util.Contracts; @@ -123,7 +124,8 @@ public BeanMetaDataManager(ConstraintHelper constraintHelper, ValueExtractorManager valueExtractorManager, ValidationOrderGenerator validationOrderGenerator, List optionalMetaDataProviders, - MethodValidationConfiguration methodValidationConfiguration) { + MethodValidationConfiguration methodValidationConfiguration, + JavaBeanPropertyAccessorFactory propertyAccessorFactory) { this.constraintHelper = constraintHelper; this.executableHelper = executableHelper; this.typeResolutionHelper = typeResolutionHelper; @@ -147,7 +149,8 @@ public BeanMetaDataManager(ConstraintHelper constraintHelper, constraintHelper, typeResolutionHelper, valueExtractorManager, - annotationProcessingOptions + annotationProcessingOptions, + propertyAccessorFactory ); List tmpMetaDataProviders = new ArrayList<>( optionalMetaDataProviders.size() + 1 ); // We add the annotation based metadata provider at the first position so that the entire metadata model is assembled diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/AnnotationMetaDataProvider.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/AnnotationMetaDataProvider.java index d3e0a42cf0..ba8d1850b9 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/AnnotationMetaDataProvider.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/AnnotationMetaDataProvider.java @@ -66,6 +66,7 @@ import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; import org.hibernate.validator.internal.properties.javabean.JavaBeanField; import org.hibernate.validator.internal.properties.javabean.JavaBeanParameter; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -92,19 +93,22 @@ public class AnnotationMetaDataProvider implements MetaDataProvider { private final ConstraintHelper constraintHelper; private final TypeResolutionHelper typeResolutionHelper; - private final AnnotationProcessingOptions annotationProcessingOptions; private final ValueExtractorManager valueExtractorManager; + private final AnnotationProcessingOptions annotationProcessingOptions; + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; private final BeanConfiguration objectBeanConfiguration; public AnnotationMetaDataProvider(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager, - AnnotationProcessingOptions annotationProcessingOptions) { + AnnotationProcessingOptions annotationProcessingOptions, + JavaBeanPropertyAccessorFactory propertyAccessorFactory) { this.constraintHelper = constraintHelper; this.typeResolutionHelper = typeResolutionHelper; this.valueExtractorManager = valueExtractorManager; this.annotationProcessingOptions = annotationProcessingOptions; + this.propertyAccessorFactory = propertyAccessorFactory; this.objectBeanConfiguration = retrieveBeanConfiguration( Object.class ); } @@ -220,7 +224,7 @@ private Set getFieldMetaData(Class beanClass) { continue; } - JavaBeanField javaBeanField = new JavaBeanField( field ); + JavaBeanField javaBeanField = new JavaBeanField( propertyAccessorFactory, field ); if ( annotationProcessingOptions.areMemberConstraintsIgnoredFor( javaBeanField ) ) { continue; @@ -301,7 +305,7 @@ private Set getMetaData(Executable[] executableElements) * given element. */ private ConstrainedExecutable findExecutableMetaData(Executable executable) { - JavaBeanExecutable javaBeanExecutable = JavaBeanExecutable.of( executable ); + JavaBeanExecutable javaBeanExecutable = JavaBeanExecutable.of( propertyAccessorFactory, executable ); List parameterConstraints = getParameterMetaData( javaBeanExecutable ); Map>> executableConstraints = findConstraints( diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/XmlMetaDataProvider.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/XmlMetaDataProvider.java index 9cef432d79..4298b23036 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/XmlMetaDataProvider.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/provider/XmlMetaDataProvider.java @@ -17,6 +17,7 @@ import org.hibernate.validator.internal.metadata.raw.BeanConfiguration; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.stereotypes.Immutable; @@ -40,11 +41,12 @@ public class XmlMetaDataProvider implements MetaDataProvider { public XmlMetaDataProvider(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager, + JavaBeanPropertyAccessorFactory propertyAccessorFactory, Set mappingStreams, ClassLoader externalClassLoader) { MappingXmlParser mappingParser = new MappingXmlParser( constraintHelper, typeResolutionHelper, valueExtractorManager, - externalClassLoader ); + propertyAccessorFactory, externalClassLoader ); mappingParser.parse( mappingStreams ); configuredBeans = CollectionHelper.toImmutableMap( createBeanConfigurations( mappingParser ) ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBean.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBean.java deleted file mode 100644 index ff9dd436dc..0000000000 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBean.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Hibernate Validator, declare and validate application constraints - * - * License: Apache License, Version 2.0 - * See the license.txt file in the root directory or . - */ -package org.hibernate.validator.internal.properties.javabean; - -import java.util.Arrays; -import java.util.stream.Stream; - -import org.hibernate.validator.internal.properties.Property; -import org.hibernate.validator.internal.properties.ConstrainableType; -import org.hibernate.validator.internal.util.ReflectionHelper; - -/** - * @author Marko Bekhta - */ -public class JavaBean implements ConstrainableType { - - private final Class clazz; - - public JavaBean(Class clazz) { - this.clazz = clazz; - } - - public Stream getFieldProperties() { - return Arrays.stream( clazz.getDeclaredFields() ) - .map( JavaBeanField::new ); - } - - public Stream getGetterProperties() { - return Arrays.stream( clazz.getDeclaredMethods() ) - .filter( ReflectionHelper::isGetterMethod ) - .map( JavaBeanGetter::new ); - } -} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java index 0c307ef696..a7011f786b 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java @@ -20,6 +20,7 @@ import java.util.List; import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; @@ -46,17 +47,17 @@ public abstract class JavaBeanExecutable implements Callab this.parameters = getParameters( executable ); } - public static JavaBeanExecutable of(Executable executable) { + public static JavaBeanExecutable of(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Executable executable) { if ( executable instanceof Constructor ) { return new JavaBeanConstructor( (Constructor) executable ); } - return of( ( (Method) executable ) ); + return of( propertyAccessorFactory, ( (Method) executable ) ); } - public static JavaBeanMethod of(Method method) { + public static JavaBeanMethod of(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Method method) { if ( ReflectionHelper.isGetterMethod( method ) ) { - return new JavaBeanGetter( method ); + return new JavaBeanGetter( propertyAccessorFactory, method ); } return new JavaBeanMethod( method ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanField.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanField.java index 647a33a3de..b0152d8720 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanField.java +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanField.java @@ -11,24 +11,24 @@ import java.lang.reflect.Field; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; -import java.security.AccessController; -import java.security.PrivilegedAction; -import org.hibernate.validator.HibernateValidatorPermission; import org.hibernate.validator.internal.properties.PropertyAccessor; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField; /** * @author Marko Bekhta */ public class JavaBeanField implements org.hibernate.validator.internal.properties.Field, JavaBeanAnnotatedConstrainable { + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; + private final Field field; private final Type typeForValidatorResolution; private final Type type; - public JavaBeanField(Field field) { + public JavaBeanField(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Field field) { + this.propertyAccessorFactory = propertyAccessorFactory; this.field = field; this.type = ReflectionHelper.typeOf( field ); this.typeForValidatorResolution = ReflectionHelper.boxedType( this.type ); @@ -86,7 +86,7 @@ public TypeVariable[] getTypeParameters() { @Override public PropertyAccessor createAccessor() { - return new FieldAccessor( field ); + return propertyAccessorFactory.forField( field ); } @Override @@ -122,41 +122,5 @@ public String toString() { return getName(); } - private static class FieldAccessor implements PropertyAccessor { - - private Field accessibleField; - - private FieldAccessor(Field field) { - this.accessibleField = getAccessible( field ); - } - - @Override - public Object getValueFrom(Object bean) { - return ReflectionHelper.getValue( accessibleField, bean ); - } - } - /** - * Returns an accessible copy of the given member. - */ - private static Field getAccessible(Field original) { - SecurityManager sm = System.getSecurityManager(); - if ( sm != null ) { - sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); - } - - Class clazz = original.getDeclaringClass(); - - return run( GetDeclaredField.andMakeAccessible( clazz, original.getName() ) ); - } - - /** - * Runs the given privileged action, using a privileged block if required. - *

- * NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary - * privileged actions within HV's protection domain. - */ - private static T run(PrivilegedAction action) { - return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); - } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanGetter.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanGetter.java index a7084b1f9e..98ec108f4d 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanGetter.java +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanGetter.java @@ -7,22 +7,21 @@ package org.hibernate.validator.internal.properties.javabean; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; -import org.hibernate.validator.HibernateValidatorPermission; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; import org.hibernate.validator.internal.properties.Getter; import org.hibernate.validator.internal.properties.PropertyAccessor; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod; /** * @author Marko Bekhta */ public class JavaBeanGetter extends JavaBeanMethod implements Getter { + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; + private final String name; /** @@ -33,14 +32,15 @@ public class JavaBeanGetter extends JavaBeanMethod implements Getter { */ private final Class declaringClass; - public JavaBeanGetter(Method method) { - super( method ); - this.name = ReflectionHelper.getPropertyName( method ); - this.declaringClass = method.getDeclaringClass(); + public JavaBeanGetter(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Method method) { + this( propertyAccessorFactory, method.getDeclaringClass(), method ); } - public JavaBeanGetter(Class declaringClass, Method method) { + public JavaBeanGetter(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Class declaringClass, Method method) { super( method ); + + this.propertyAccessorFactory = propertyAccessorFactory; + this.name = ReflectionHelper.getPropertyName( method ); this.declaringClass = declaringClass; } @@ -79,7 +79,7 @@ public ConstrainedElementKind getConstrainedElementKind() { @Override public PropertyAccessor createAccessor() { - return new GetterAccessor( executable ); + return propertyAccessorFactory.forGetter( executable ); } @Override @@ -105,43 +105,4 @@ public int hashCode() { result = 31 * result + this.name.hashCode(); return result; } - - private static class GetterAccessor implements PropertyAccessor { - - private Method accessibleGetter; - - private GetterAccessor(Method getter) { - this.accessibleGetter = getAccessible( getter ); - } - - @Override - public Object getValueFrom(Object bean) { - return ReflectionHelper.getValue( accessibleGetter, bean ); - } - } - - /** - * Returns an accessible copy of the given method. - */ - private static Method getAccessible(Method original) { - SecurityManager sm = System.getSecurityManager(); - if ( sm != null ) { - sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); - } - - Class clazz = original.getDeclaringClass(); - Method accessibleMethod = run( GetDeclaredMethod.andMakeAccessible( clazz, original.getName() ) ); - - return accessibleMethod; - } - - /** - * Runs the given privileged action, using a privileged block if required. - *

- * NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary - * privileged actions within HV's protection domain. - */ - private static T run(PrivilegedAction action) { - return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); - } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/JavaBeanPropertyAccessorFactory.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/JavaBeanPropertyAccessorFactory.java new file mode 100644 index 0000000000..1a03f85081 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/JavaBeanPropertyAccessorFactory.java @@ -0,0 +1,37 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal.properties.javabean.accessors; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.hibernate.validator.internal.engine.ConfigurationImpl; +import org.hibernate.validator.internal.properties.PropertyAccessor; + +/** + * @author Marko Bekhta + */ +public interface JavaBeanPropertyAccessorFactory { + + static JavaBeanPropertyAccessorFactory of(ConfigurationImpl configuration) { + if ( configuration == null ) { + return ReflectionJavaBeanPropertyAccessorFactory.INSTANCE; + } + switch ( configuration.getPropertyAccessKind() ) { + case METHOD_HANDLES: + return new MethodHandleJavaBeanPropertyAccessorFactory( configuration.getLookup() ); + case REFLECTION: + return ReflectionJavaBeanPropertyAccessorFactory.INSTANCE; + default: + throw new IllegalStateException( "Unsupported property access kind." ); + } + } + + PropertyAccessor forField(Field field); + + PropertyAccessor forGetter(Method getter); +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/MethodHandleJavaBeanPropertyAccessorFactory.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/MethodHandleJavaBeanPropertyAccessorFactory.java new file mode 100644 index 0000000000..27fda32dcf --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/MethodHandleJavaBeanPropertyAccessorFactory.java @@ -0,0 +1,132 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal.properties.javabean.accessors; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.hibernate.validator.HibernateValidatorPermission; +import org.hibernate.validator.internal.properties.PropertyAccessor; +import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.util.logging.Log; +import org.hibernate.validator.internal.util.logging.LoggerFactory; +import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField; +import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod; + +/** + * @author Marko Bekhta + */ +public class MethodHandleJavaBeanPropertyAccessorFactory implements JavaBeanPropertyAccessorFactory { + + private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); + + private final MethodHandles.Lookup lookup; + + public MethodHandleJavaBeanPropertyAccessorFactory(MethodHandles.Lookup lookup) { + this.lookup = lookup; + } + + + @Override + public PropertyAccessor forField(Field field) { + return new FieldAccessor( lookup, field ); + } + + @Override + public PropertyAccessor forGetter(Method getter) { + return new GetterAccessor( lookup, getter ); + } + + private abstract static class AbstractAccessor implements PropertyAccessor { + + protected final MethodHandle accessibleFieldHandle; + + private AbstractAccessor(MethodHandle accessibleFieldHandle) { + this.accessibleFieldHandle = accessibleFieldHandle; + } + + @Override + public Object getValueFrom(Object bean) { + return ReflectionHelper.getValue( accessibleFieldHandle, bean ); + } + } + + private static class FieldAccessor extends AbstractAccessor { + + private FieldAccessor(MethodHandles.Lookup lookup, Field field) { + super( unreflectField( lookup, field ) ); + } + + private static MethodHandle unreflectField(MethodHandles.Lookup lookup, Field field) { + try { + return lookup.unreflectGetter( getAccessible( field ) ); + } + catch (IllegalAccessException e) { + throw LOG.getCannotCustructMethodHandleForMember( field ); + } + } + } + + private static class GetterAccessor extends AbstractAccessor { + + private GetterAccessor(MethodHandles.Lookup lookup, Method method) { + super( unreflectMethod( lookup, method ) ); + } + + private static MethodHandle unreflectMethod(MethodHandles.Lookup lookup, Method method) { + try { + return lookup.unreflect( getAccessible( method ) ); + } + catch (IllegalAccessException e) { + throw LOG.getCannotCustructMethodHandleForMember( method ); + } + } + } + + /** + * Returns an accessible copy of the given method. + */ + private static Method getAccessible(Method original) { + SecurityManager sm = System.getSecurityManager(); + if ( sm != null ) { + sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); + } + + Class clazz = original.getDeclaringClass(); + Method accessibleMethod = run( GetDeclaredMethod.andMakeAccessible( clazz, original.getName() ) ); + + return accessibleMethod; + } + + /** + * Returns an accessible copy of the given member. + */ + private static Field getAccessible(Field original) { + SecurityManager sm = System.getSecurityManager(); + if ( sm != null ) { + sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); + } + + Class clazz = original.getDeclaringClass(); + + return run( GetDeclaredField.andMakeAccessible( clazz, original.getName() ) ); + } + + /** + * Runs the given privileged action, using a privileged block if required. + *

+ * NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary + * privileged actions within HV's protection domain. + */ + private static T run(PrivilegedAction action) { + return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/ReflectionJavaBeanPropertyAccessorFactory.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/ReflectionJavaBeanPropertyAccessorFactory.java new file mode 100644 index 0000000000..6bdd023445 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/ReflectionJavaBeanPropertyAccessorFactory.java @@ -0,0 +1,103 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal.properties.javabean.accessors; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.hibernate.validator.HibernateValidatorPermission; +import org.hibernate.validator.internal.properties.PropertyAccessor; +import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField; +import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod; + +/** + * @author Marko Bekhta + */ +public class ReflectionJavaBeanPropertyAccessorFactory implements JavaBeanPropertyAccessorFactory { + + public static ReflectionJavaBeanPropertyAccessorFactory INSTANCE = new ReflectionJavaBeanPropertyAccessorFactory(); + + @Override + public PropertyAccessor forField(Field field) { + return new FieldAccessor( field ); + } + + @Override + public PropertyAccessor forGetter(Method getter) { + return new GetterAccessor( getter ); + } + + private static class FieldAccessor implements PropertyAccessor { + + private Field accessibleField; + + private FieldAccessor(Field field) { + this.accessibleField = getAccessible( field ); + } + + @Override + public Object getValueFrom(Object bean) { + return ReflectionHelper.getValue( accessibleField, bean ); + } + } + + private static class GetterAccessor implements PropertyAccessor { + + private Method accessibleGetter; + + private GetterAccessor(Method getter) { + this.accessibleGetter = getAccessible( getter ); + } + + @Override + public Object getValueFrom(Object bean) { + return ReflectionHelper.getValue( accessibleGetter, bean ); + } + } + + /** + * Returns an accessible copy of the given method. + */ + private static Method getAccessible(Method original) { + SecurityManager sm = System.getSecurityManager(); + if ( sm != null ) { + sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); + } + + Class clazz = original.getDeclaringClass(); + Method accessibleMethod = run( GetDeclaredMethod.andMakeAccessible( clazz, original.getName() ) ); + + return accessibleMethod; + } + + /** + * Returns an accessible copy of the given member. + */ + private static Field getAccessible(Field original) { + SecurityManager sm = System.getSecurityManager(); + if ( sm != null ) { + sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); + } + + Class clazz = original.getDeclaringClass(); + + return run( GetDeclaredField.andMakeAccessible( clazz, original.getName() ) ); + } + + /** + * Runs the given privileged action, using a privileged block if required. + *

+ * NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary + * privileged actions within HV's protection domain. + */ + private static T run(PrivilegedAction action) { + return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/package-info.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/package-info.java new file mode 100644 index 0000000000..184c1e5dd3 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/accessors/package-info.java @@ -0,0 +1,8 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ + +package org.hibernate.validator.internal.properties.javabean.accessors; diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/ReflectionHelper.java b/engine/src/main/java/org/hibernate/validator/internal/util/ReflectionHelper.java index b9e3d0597d..acca29888d 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/util/ReflectionHelper.java +++ b/engine/src/main/java/org/hibernate/validator/internal/util/ReflectionHelper.java @@ -8,6 +8,7 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -222,6 +223,15 @@ public static Object getValue(Method method, Object object) { } } + public static Object getValue(MethodHandle methodHandle, Object object) { + try { + return methodHandle.invoke( object ); + } + catch (Throwable e) { + throw LOG.getUnableToAccessPropertyException( e ); + } + } + /** * Indicates whether the given type represents a collection of elements or not (i.e. whether it is an * {@code Iterable}, {@code Map} or array type). diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java b/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java index 7a0da1e309..375a3a053a 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java +++ b/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java @@ -864,4 +864,10 @@ ConstraintDefinitionException getConstraintValidatorDefinitionConstraintMismatch @Message(id = 245, value = "Allowed constraint element types are FIELD and GETTER, but instead received %1$s.") AssertionError getUnsupportedConstraintElementType(ConstrainedElement.ConstrainedElementKind kind); + + @Message(id = 246, value = "Cannot construct a method handle for %1$s while creating property accessor.") + IllegalStateException getCannotCustructMethodHandleForMember(Member member); + + @Message(id = 247, value = "Unable to access property.") + ValidationException getUnableToAccessPropertyException(@Cause Throwable e); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/BeanStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/BeanStaxBuilder.java index e551a46485..30ab8bcfc8 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/BeanStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/BeanStaxBuilder.java @@ -29,6 +29,7 @@ import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; @@ -140,7 +141,7 @@ private ConstrainedConstructorStaxBuilder getNewConstrainedConstructorStaxBuilde return new ConstrainedConstructorStaxBuilder( classLoadingHelper, constraintHelper, typeResolutionHelper, valueExtractorManager, defaultPackageStaxBuilder, annotationProcessingOptions ); } - void build(Set> processedClasses, Map, Set> constrainedElementsByType) { + void build(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Set> processedClasses, Map, Set> constrainedElementsByType) { Class beanClass = classLoadingHelper.loadClass( className, defaultPackageStaxBuilder.build().orElse( "" ) ); checkClassHasNotBeenProcessed( processedClasses, beanClass ); @@ -165,7 +166,7 @@ void build(Set> processedClasses, Map, Set addConstrainedElements( constrainedElementsByType, beanClass, constrainedFieldStaxBuilders.stream() - .map( builder -> builder.build( beanClass, alreadyProcessedFieldNames ) ) + .map( builder -> builder.build( propertyAccessorFactory, beanClass, alreadyProcessedFieldNames ) ) .collect( Collectors.toList() ) ); @@ -174,7 +175,7 @@ void build(Set> processedClasses, Map, Set constrainedElementsByType, beanClass, constrainedGetterStaxBuilders.stream() - .map( builder -> builder.build( beanClass, alreadyProcessedGetterNames ) ) + .map( builder -> builder.build( propertyAccessorFactory, beanClass, alreadyProcessedGetterNames ) ) .collect( Collectors.toList() ) ); @@ -183,7 +184,7 @@ void build(Set> processedClasses, Map, Set constrainedElementsByType, beanClass, constrainedMethodStaxBuilders.stream() - .map( builder -> builder.build( beanClass, alreadyProcessedMethods ) ) + .map( builder -> builder.build( propertyAccessorFactory, beanClass, alreadyProcessedMethods ) ) .collect( Collectors.toList() ) ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedFieldStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedFieldStaxBuilder.java index bb0a350084..59e4a0329b 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedFieldStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedFieldStaxBuilder.java @@ -26,6 +26,7 @@ import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.properties.javabean.JavaBeanField; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -63,7 +64,7 @@ protected String getAcceptableQName() { return FIELD_QNAME_LOCAL_PART; } - ConstrainedField build(Class beanClass, List alreadyProcessedFieldNames) { + ConstrainedField build(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Class beanClass, List alreadyProcessedFieldNames) { if ( alreadyProcessedFieldNames.contains( mainAttributeValue ) ) { throw LOG.getIsDefinedTwiceInMappingXmlForBeanException( mainAttributeValue, beanClass ); } @@ -71,7 +72,7 @@ ConstrainedField build(Class beanClass, List alreadyProcessedFieldNam alreadyProcessedFieldNames.add( mainAttributeValue ); } Field field = findField( beanClass, mainAttributeValue ); - JavaBeanField javaBeanField = new JavaBeanField( field ); + JavaBeanField javaBeanField = new JavaBeanField( propertyAccessorFactory, field ); ConstraintLocation constraintLocation = ConstraintLocation.forField( javaBeanField ); Set> metaConstraints = constraintTypeStaxBuilders.stream() diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedGetterStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedGetterStaxBuilder.java index 3969c10577..9c6630f637 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedGetterStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedGetterStaxBuilder.java @@ -28,6 +28,7 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -65,7 +66,7 @@ protected String getAcceptableQName() { return GETTER_QNAME_LOCAL_PART; } - ConstrainedExecutable build(Class beanClass, List alreadyProcessedGetterNames) { + ConstrainedExecutable build(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Class beanClass, List alreadyProcessedGetterNames) { if ( alreadyProcessedGetterNames.contains( mainAttributeValue ) ) { throw LOG.getIsDefinedTwiceInMappingXmlForBeanException( mainAttributeValue, beanClass ); } @@ -73,7 +74,7 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedGet alreadyProcessedGetterNames.add( mainAttributeValue ); } Method getter = findGetter( beanClass, mainAttributeValue ); - JavaBeanGetter javaBeanGetter = new JavaBeanGetter( beanClass, getter ); + JavaBeanGetter javaBeanGetter = new JavaBeanGetter( propertyAccessorFactory, beanClass, getter ); ConstraintLocation constraintLocation = ConstraintLocation.forGetter( javaBeanGetter ); Set> metaConstraints = constraintTypeStaxBuilders.stream() diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedMethodStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedMethodStaxBuilder.java index 4a78d244bc..b066547542 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedMethodStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedMethodStaxBuilder.java @@ -27,6 +27,7 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -68,7 +69,7 @@ public String getMethodName() { return mainAttributeValue; } - ConstrainedExecutable build(Class beanClass, List alreadyProcessedMethods) { + ConstrainedExecutable build(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Class beanClass, List alreadyProcessedMethods) { Class[] parameterTypes = constrainedParameterStaxBuilders.stream() .map( builder -> builder.getParameterType( beanClass ) ) .toArray( Class[]::new ); @@ -97,7 +98,7 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedMet else { alreadyProcessedMethods.add( method ); } - JavaBeanExecutable executable = JavaBeanExecutable.of( method ); + JavaBeanExecutable executable = JavaBeanExecutable.of( propertyAccessorFactory, method ); // ignore annotations if ( ignoreAnnotations.isPresent() ) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintMappingsStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintMappingsStaxBuilder.java index 50ac58eeb8..5c9e97286f 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintMappingsStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintMappingsStaxBuilder.java @@ -19,6 +19,7 @@ import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.xml.AbstractStaxBuilder; @@ -89,8 +90,8 @@ private ConstraintDefinitionStaxBuilder getNewConstraintDefinitionStaxBuilder() return new ConstraintDefinitionStaxBuilder( classLoadingHelper, constraintHelper, defaultPackageStaxBuilder ); } - public void build(Set> processedClasses, Map, Set> constrainedElementsByType, Set alreadyProcessedConstraintDefinitions) { + public void build(JavaBeanPropertyAccessorFactory propertyAccessorFactory, Set> processedClasses, Map, Set> constrainedElementsByType, Set alreadyProcessedConstraintDefinitions) { constraintDefinitionStaxBuilders.forEach( builder -> builder.build( alreadyProcessedConstraintDefinitions ) ); - beanStaxBuilders.forEach( builder -> builder.build( processedClasses, constrainedElementsByType ) ); + beanStaxBuilders.forEach( builder -> builder.build( propertyAccessorFactory, processedClasses, constrainedElementsByType ) ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/MappingXmlParser.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/MappingXmlParser.java index 75cbb1bd59..5c302aae08 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/MappingXmlParser.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/MappingXmlParser.java @@ -31,6 +31,7 @@ import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.properties.javabean.accessors.JavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; @@ -54,6 +55,7 @@ public class MappingXmlParser { private final ConstraintHelper constraintHelper; private final TypeResolutionHelper typeResolutionHelper; private final ValueExtractorManager valueExtractorManager; + private final JavaBeanPropertyAccessorFactory propertyAccessorFactory; private final AnnotationProcessingOptionsImpl annotationProcessingOptions; private final Map, List>> defaultSequences; private final Map, Set> constrainedElements; @@ -75,10 +77,11 @@ private static Map getSchemasByVersion() { } public MappingXmlParser(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager, - ClassLoader externalClassLoader) { + JavaBeanPropertyAccessorFactory propertyAccessorFactory, ClassLoader externalClassLoader) { this.constraintHelper = constraintHelper; this.typeResolutionHelper = typeResolutionHelper; this.valueExtractorManager = valueExtractorManager; + this.propertyAccessorFactory = propertyAccessorFactory; this.annotationProcessingOptions = new AnnotationProcessingOptionsImpl(); this.defaultSequences = newHashMap(); this.constrainedElements = newHashMap(); @@ -128,7 +131,7 @@ public final void parse(Set mappingStreams) { while ( xmlEventReader.hasNext() ) { constraintMappingsStaxBuilder.process( xmlEventReader, xmlEventReader.nextEvent() ); } - constraintMappingsStaxBuilder.build( processedClasses, constrainedElements, alreadyProcessedConstraintDefinitions ); + constraintMappingsStaxBuilder.build( propertyAccessorFactory, processedClasses, constrainedElements, alreadyProcessedConstraintDefinitions ); xmlEventReader.close(); in.reset(); } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/path/PathImplTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/path/PathImplTest.java index 1153454aa4..8ed8c31416 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/path/PathImplTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/path/PathImplTest.java @@ -36,6 +36,7 @@ import org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -199,7 +200,8 @@ public void testCreationOfExecutablePath() throws Exception { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); ExecutableMetaData executableMetaData = beanMetaDataManager.getBeanMetaData( Container.class ) diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/BeanMetaDataManagerTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/BeanMetaDataManagerTest.java index 9b402186b8..5e8219cfd8 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/BeanMetaDataManagerTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/BeanMetaDataManagerTest.java @@ -29,6 +29,7 @@ import org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -58,7 +59,8 @@ public void setUpBeanMetaDataManager() { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ExecutableMetaDataTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ExecutableMetaDataTest.java index 170e8a64d2..51f309d2c5 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ExecutableMetaDataTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ExecutableMetaDataTest.java @@ -32,6 +32,7 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -63,7 +64,8 @@ public void setupBeanMetaData() { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); beanMetaData = beanMetaDataManager.getBeanMetaData( CustomerRepositoryExt.class ); diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ParameterMetaDataTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ParameterMetaDataTest.java index bccf0c208b..60d4632b3e 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ParameterMetaDataTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/ParameterMetaDataTest.java @@ -33,6 +33,7 @@ import org.hibernate.validator.internal.metadata.aggregated.ParameterMetaData; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -63,7 +64,8 @@ public void setupBeanMetaData() { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); beanMetaData = beanMetaDataManager.getBeanMetaData( CustomerRepository.class ); @@ -133,7 +135,8 @@ public void parameterNameInInheritanceHierarchy() throws Exception { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); BeanMetaData localBeanMetaData = beanMetaDataManager.getBeanMetaData( ServiceImpl.class ); diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/PropertyMetaDataTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/PropertyMetaDataTest.java index fe2577ea2e..282507fcc2 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/PropertyMetaDataTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/aggregated/PropertyMetaDataTest.java @@ -24,6 +24,7 @@ import org.hibernate.validator.internal.metadata.aggregated.PropertyMetaData; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.provider.MetaDataProvider; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -47,7 +48,8 @@ public void setupBeanMetaDataManager() { new ValueExtractorManager( Collections.emptySet() ), new ValidationOrderGenerator(), Collections.emptyList(), - new MethodValidationConfiguration.Builder().build() + new MethodValidationConfiguration.Builder().build(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/core/MetaConstraintTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/core/MetaConstraintTest.java index 436f7e8b3a..6518e75212 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/core/MetaConstraintTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/core/MetaConstraintTest.java @@ -21,6 +21,7 @@ import org.hibernate.validator.internal.metadata.location.ConstraintLocation; import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.testutil.TestForIssue; @@ -51,14 +52,14 @@ public void setUp() throws Exception { @TestForIssue(jiraKey = "HV-930") public void two_meta_constraints_for_the_same_constraint_should_be_equal() throws Exception { ConstraintDescriptorImpl constraintDescriptor1 = new ConstraintDescriptorImpl<>( - constraintHelper, JavaBeanExecutable.of( barMethod ), constraintAnnotationDescriptor, ConstraintLocationKind.METHOD + constraintHelper, JavaBeanExecutable.of( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, barMethod ), constraintAnnotationDescriptor, ConstraintLocationKind.METHOD ); ConstraintLocation location1 = ConstraintLocation.forClass( Foo.class ); MetaConstraint metaConstraint1 = MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor1, location1 ); ConstraintDescriptorImpl constraintDescriptor2 = new ConstraintDescriptorImpl<>( - constraintHelper, JavaBeanExecutable.of( barMethod ), constraintAnnotationDescriptor, ConstraintLocationKind.METHOD + constraintHelper, JavaBeanExecutable.of( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, barMethod ), constraintAnnotationDescriptor, ConstraintLocationKind.METHOD ); ConstraintLocation location2 = ConstraintLocation.forClass( Foo.class ); MetaConstraint metaConstraint2 = MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor2, location2 ); diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/location/ConstraintLocationTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/location/ConstraintLocationTest.java index 0bbca776e3..75548cc454 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/location/ConstraintLocationTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/location/ConstraintLocationTest.java @@ -12,6 +12,7 @@ import org.hibernate.validator.internal.metadata.location.ConstraintLocation; import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.testutil.TestForIssue; import org.testng.annotations.Test; @@ -33,8 +34,8 @@ public void two_constraint_locations_for_the_same_type_should_be_equal() { @TestForIssue(jiraKey = "HV-930") public void two_constraint_locations_for_the_same_member_should_be_equal() throws Exception { Method getter = Foo.class.getMethod( "getBar" ); - ConstraintLocation location1 = ConstraintLocation.forGetter( new JavaBeanGetter( getter ) ); - ConstraintLocation location2 = ConstraintLocation.forGetter( new JavaBeanGetter( getter ) ); + ConstraintLocation location1 = ConstraintLocation.forGetter( new JavaBeanGetter( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, getter ) ); + ConstraintLocation location2 = ConstraintLocation.forGetter( new JavaBeanGetter( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, getter ) ); assertEquals( location1, location2, "Two constraint locations for the same type should be equal" ); } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTest.java index 9693602727..c715cb36c3 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTest.java @@ -42,6 +42,7 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.testutil.TestForIssue; @@ -63,7 +64,8 @@ public void setUpProvider() { new ConstraintHelper(), new TypeResolutionHelper(), new ValueExtractorManager( Collections.emptySet() ), - new AnnotationProcessingOptionsImpl() + new AnnotationProcessingOptionsImpl(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); } @@ -105,6 +107,7 @@ public void testGetCrossParameterMetaData() throws Exception { assertThat( createEvent.getCallable() ).isEqualTo( JavaBeanExecutable.of( + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, Calendar.class.getMethod( "createEvent", LocalDate.class, diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTestBase.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTestBase.java index bf6f716428..be29e17dd0 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTestBase.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/AnnotationMetaDataProviderTestBase.java @@ -19,6 +19,7 @@ import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; import org.hibernate.validator.internal.properties.javabean.JavaBeanField; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; /** * @author Gunnar Morling @@ -64,10 +65,10 @@ protected ConstrainedElement findConstrainedElement(BeanConfiguration beanCon Constrainable constrainable; if ( member instanceof Field ) { - constrainable = new JavaBeanField( (Field) member ); + constrainable = new JavaBeanField( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, (Field) member ); } else { - constrainable = JavaBeanExecutable.of( (Executable) member ); + constrainable = JavaBeanExecutable.of( ReflectionJavaBeanPropertyAccessorFactory.INSTANCE, (Executable) member ); } for ( ConstrainedElement constrainedElement : beanConfiguration.getConstrainedElements() ) { diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/TypeAnnotationMetaDataRetrievalTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/TypeAnnotationMetaDataRetrievalTest.java index 3d7721ca77..5dc9f4b660 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/TypeAnnotationMetaDataRetrievalTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/metadata/provider/TypeAnnotationMetaDataRetrievalTest.java @@ -27,6 +27,7 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -46,7 +47,8 @@ public void setup() { new ConstraintHelper(), new TypeResolutionHelper(), new ValueExtractorManager( Collections.emptySet() ), - new AnnotationProcessingOptionsImpl() + new AnnotationProcessingOptionsImpl(), + ReflectionJavaBeanPropertyAccessorFactory.INSTANCE ); } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/properties/javabean/PropertyAccessKindTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/properties/javabean/PropertyAccessKindTest.java new file mode 100644 index 0000000000..eec5e6dfae --- /dev/null +++ b/engine/src/test/java/org/hibernate/validator/test/internal/properties/javabean/PropertyAccessKindTest.java @@ -0,0 +1,56 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.test.internal.properties.javabean; + +import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertThat; +import static org.hibernate.validator.testutil.ConstraintViolationAssert.violationOf; + +import java.lang.invoke.MethodHandles; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Positive; + +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.HibernateValidatorConfiguration.PropertyAccessKind; + +import org.testng.annotations.Test; + +public class PropertyAccessKindTest { + + @Test + public void testConfigurationAllowsToUseMethodHandles() { + Validator validator = Validation.byProvider( HibernateValidator.class ) + .configure() + .propertyAccessKind( PropertyAccessKind.METHOD_HANDLES ) + .externalLookup( MethodHandles.lookup() ) + .buildValidatorFactory() + .getValidator(); + Set> constraintViolations = validator.validate( new Foo() ); + + assertThat( constraintViolations ).containsOnlyViolations( + violationOf( NotBlank.class ).withProperty( "foo" ), + violationOf( Email.class ).withProperty( "foo" ), + violationOf( Positive.class ).withProperty( "bar" ) + ); + } + + private static class Foo { + @NotBlank + @Email + private String foo = "\t"; + + @Positive + public int getBar() { + return -1; + } + } +} diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/xml/MappingXmlParserTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/xml/MappingXmlParserTest.java index 0ef2a724f0..3d9773faaa 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/xml/MappingXmlParserTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/xml/MappingXmlParserTest.java @@ -25,6 +25,7 @@ import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorDescriptor; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; +import org.hibernate.validator.internal.properties.javabean.accessors.ReflectionJavaBeanPropertyAccessorFactory; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.xml.mapping.MappingXmlParser; import org.hibernate.validator.testutil.TestForIssue; @@ -43,7 +44,7 @@ public class MappingXmlParserTest { public void setupParserHelper() { constraintHelper = new ConstraintHelper(); xmlMappingParser = new MappingXmlParser( - constraintHelper, new TypeResolutionHelper(), new ValueExtractorManager( Collections.emptySet() ), null + constraintHelper, new TypeResolutionHelper(), new ValueExtractorManager( Collections.emptySet() ), ReflectionJavaBeanPropertyAccessorFactory.INSTANCE,null ); }