diff --git a/engine/src/main/java/org/hibernate/validator/cfg/context/PropertyTarget.java b/engine/src/main/java/org/hibernate/validator/cfg/context/PropertyTarget.java index 3fae3760fa..3546ce6dd0 100644 --- a/engine/src/main/java/org/hibernate/validator/cfg/context/PropertyTarget.java +++ b/engine/src/main/java/org/hibernate/validator/cfg/context/PropertyTarget.java @@ -21,15 +21,46 @@ public interface PropertyTarget { *

* Until this method is called constraints apply on class level. After calling this method constraints * apply on the specified property with the given access type. - *

*

* A given property may only be configured once. - *

* * @param property The property on which to apply the following constraints (Java Bean notation). * @param type The access type (field/property). * * @return A creational context representing the selected property. + * + * @deprecated Since 6.1. Planned for removal. Use either {@link PropertyTarget#field(String)} or + * {@link PropertyTarget#getter(String)} instead. */ + @Deprecated PropertyConstraintMappingContext property(String property, ElementType type); + + /** + * Selects a field to which the next operations shall apply. + *

+ * Until this method is called constraints apply on class level. After calling this method constraints + * apply on the specified field property. + *

+ * A given field may only be configured once. + * + * @param property The field name that represents a property on which to apply the following constraints. + * + * @return A creational context representing the selected field property. + */ + PropertyConstraintMappingContext field(String property); + + /** + * Selects a getter to which the next operations shall apply. + *

+ * Until this method is called constraints apply on class level. After calling this method constraints + * apply on the specified getter property. + *

+ * A given getter may only be configured once. + * + * @param property The getter property name (using the Java Bean notation, e.g. {@code name} to address {@code getName()}) + * that represents a property on which to apply the following constraints. + * + * @return A creational context representing the selected getter property. + */ + PropertyConstraintMappingContext getter(String property); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/PropertyConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/AbstractPropertyConstraintMappingContextImpl.java similarity index 56% rename from engine/src/main/java/org/hibernate/validator/internal/cfg/context/PropertyConstraintMappingContextImpl.java rename to engine/src/main/java/org/hibernate/validator/internal/cfg/context/AbstractPropertyConstraintMappingContextImpl.java index dcb6681ce5..1cab16b832 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/PropertyConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/AbstractPropertyConstraintMappingContextImpl.java @@ -7,12 +7,7 @@ package org.hibernate.validator.internal.cfg.context; import java.lang.annotation.ElementType; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import org.hibernate.validator.cfg.ConstraintDef; import org.hibernate.validator.cfg.context.ConstructorConstraintMappingContext; import org.hibernate.validator.cfg.context.ContainerElementConstraintMappingContext; import org.hibernate.validator.cfg.context.MethodConstraintMappingContext; @@ -21,11 +16,8 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; -import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; -import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; -import org.hibernate.validator.internal.metadata.raw.ConstrainedField; -import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.properties.Property; import org.hibernate.validator.internal.util.TypeResolutionHelper; /** @@ -34,50 +26,27 @@ * @author Hardy Ferentschik * @author Gunnar Morling * @author Kevin Pollet <kevin.pollet@serli.com> (C) 2011 SERLI + * @author Marko Bekhta */ -final class PropertyConstraintMappingContextImpl +abstract class AbstractPropertyConstraintMappingContextImpl extends CascadableConstraintMappingContextImplBase implements PropertyConstraintMappingContext { private final TypeConstraintMappingContextImpl typeContext; // either Field or Method - private final Member member; + private final T property; private final ConstraintLocation location; - PropertyConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, Member member) { - super( typeContext.getConstraintMapping(), ReflectionHelper.typeOf( member ) ); + protected AbstractPropertyConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, T property, ConstraintLocation location) { + super( typeContext.getConstraintMapping(), property.getType() ); this.typeContext = typeContext; - this.member = member; - if ( member instanceof Field ) { - this.location = ConstraintLocation.forField( (Field) member ); - } - else { - this.location = ConstraintLocation.forGetter( (Method) member ); - } + this.property = property; + this.location = location; } @Override - protected PropertyConstraintMappingContextImpl getThis() { - return this; - } - - @Override - public PropertyConstraintMappingContext constraint(ConstraintDef definition) { - if ( member instanceof Field ) { - super.addConstraint( - ConfiguredConstraint.forProperty( - definition, member - ) - ); - } - else { - super.addConstraint( - ConfiguredConstraint.forExecutable( - definition, (Method) member - ) - ); - } + protected AbstractPropertyConstraintMappingContextImpl getThis() { return this; } @@ -88,7 +57,7 @@ public PropertyConstraintMappingContext ignoreAnnotations() { @Override public PropertyConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { - mapping.getAnnotationProcessingOptions().ignoreConstraintAnnotationsOnMember( member, ignoreAnnotations ); + mapping.getAnnotationProcessingOptions().ignoreConstraintAnnotationsOnMember( property, ignoreAnnotations ); return this; } @@ -97,6 +66,16 @@ public PropertyConstraintMappingContext property(String property, ElementType el return typeContext.property( property, elementType ); } + @Override + public PropertyConstraintMappingContext field(String property) { + return typeContext.field( property ); + } + + @Override + public PropertyConstraintMappingContext getter(String property) { + return typeContext.getter( property ); + } + @Override public ConstructorConstraintMappingContext constructor(Class... parameterTypes) { return typeContext.constructor( parameterTypes ); @@ -117,29 +96,14 @@ public ContainerElementConstraintMappingContext containerElementType(int index, return super.containerElement( this, typeContext, location, index, nestedIndexes ); } - ConstrainedElement build(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { - if ( member instanceof Field ) { - return new ConstrainedField( - ConfigurationSource.API, - (Field) member, - getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), - getTypeArgumentConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), - getCascadingMetaDataBuilder() - ); - } - else { - return new ConstrainedExecutable( - ConfigurationSource.API, - (Executable) member, - getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), - getTypeArgumentConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), - getCascadingMetaDataBuilder() - ); - } - } + abstract ConstrainedElement build(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager); @Override protected ConstraintType getConstraintType() { return ConstraintType.GENERIC; } + + protected T getProperty() { + return property; + } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConfiguredConstraint.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConfiguredConstraint.java index 8f338757fe..965c5711fa 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConfiguredConstraint.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConfiguredConstraint.java @@ -7,13 +7,8 @@ package org.hibernate.validator.internal.cfg.context; import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.security.AccessController; @@ -24,7 +19,9 @@ import org.hibernate.validator.cfg.AnnotationDef; import org.hibernate.validator.cfg.ConstraintDef; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; -import org.hibernate.validator.internal.util.ExecutableHelper; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanField; +import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; import org.hibernate.validator.internal.util.annotation.AnnotationDescriptor; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.internal.util.logging.Log; @@ -36,6 +33,7 @@ * related to its location (bean type etc.). * * @author Gunnar Morling + * @author Guillaume Smet */ class ConfiguredConstraint { @@ -46,58 +44,40 @@ class ConfiguredConstraint { private final ConstraintDef constraint; private final ConstraintLocation location; - private final ElementType elementType; - private ConfiguredConstraint(ConstraintDef constraint, ConstraintLocation location, ElementType elementType) { + private ConfiguredConstraint(ConstraintDef constraint, ConstraintLocation location) { this.constraint = constraint; this.location = location; - this.elementType = elementType; } static ConfiguredConstraint forType(ConstraintDef constraint, Class beanType) { - return new ConfiguredConstraint<>( constraint, ConstraintLocation.forClass( beanType ), ElementType.TYPE ); + return new ConfiguredConstraint<>( constraint, ConstraintLocation.forClass( beanType ) ); } - static ConfiguredConstraint forProperty(ConstraintDef constraint, Member member) { - if ( member instanceof Field ) { - return new ConfiguredConstraint<>( - constraint, - ConstraintLocation.forField( (Field) member ), - ElementType.FIELD - ); - } - else { - return new ConfiguredConstraint<>( - constraint, - ConstraintLocation.forGetter( (Method) member ), - ElementType.METHOD - ); - } + static ConfiguredConstraint forField(ConstraintDef constraint, JavaBeanField javaBeanField) { + return new ConfiguredConstraint<>( constraint, ConstraintLocation.forField( javaBeanField ) ); } - public static ConfiguredConstraint forParameter(ConstraintDef constraint, Executable executable, int parameterIndex) { - return new ConfiguredConstraint<>( - constraint, ConstraintLocation.forParameter( executable, parameterIndex ), ExecutableHelper.getElementType( executable ) - ); + static ConfiguredConstraint forGetter(ConstraintDef constraint, JavaBeanGetter javaBeanGetter) { + return forExecutable( constraint, javaBeanGetter ); } - public static ConfiguredConstraint forExecutable(ConstraintDef constraint, Executable executable) { - return new ConfiguredConstraint<>( - constraint, ConstraintLocation.forReturnValue( executable ), ExecutableHelper.getElementType( executable ) - ); + public static ConfiguredConstraint forParameter(ConstraintDef constraint, Callable callable, int parameterIndex) { + return new ConfiguredConstraint<>( constraint, ConstraintLocation.forParameter( callable, parameterIndex ) ); } - public static ConfiguredConstraint forCrossParameter(ConstraintDef constraint, Executable executable) { - return new ConfiguredConstraint<>( - constraint, ConstraintLocation.forCrossParameter( executable ), ExecutableHelper.getElementType( executable ) - ); + public static ConfiguredConstraint forExecutable(ConstraintDef constraint, Callable callable) { + return new ConfiguredConstraint<>( constraint, ConstraintLocation.forReturnValue( callable ) ); } - public static ConfiguredConstraint forTypeArgument(ConstraintDef constraint,ConstraintLocation delegate, TypeVariable typeArgument, Type typeOfAnnotatedElement) { + public static ConfiguredConstraint forCrossParameter(ConstraintDef constraint, Callable callable) { + return new ConfiguredConstraint<>( constraint, ConstraintLocation.forCrossParameter( callable ) ); + } + + public static ConfiguredConstraint forTypeArgument(ConstraintDef constraint, ConstraintLocation delegate, TypeVariable typeArgument, Type typeOfAnnotatedElement) { return new ConfiguredConstraint<>( constraint, - ConstraintLocation.forTypeArgument( delegate, typeArgument, typeOfAnnotatedElement ), - ElementType.TYPE_USE + ConstraintLocation.forTypeArgument( delegate, typeArgument, typeOfAnnotatedElement ) ); } @@ -127,10 +107,6 @@ public String toString() { return constraint.toString(); } - public ElementType getElementType() { - return elementType; - } - /** * 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 diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstraintMappingContextImplBase.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstraintMappingContextImplBase.java index 3eb7a9c92c..3598e1d70f 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstraintMappingContextImplBase.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstraintMappingContextImplBase.java @@ -73,9 +73,9 @@ private MetaConstraint asMetaConstraint(ConfiguredCons TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { ConstraintDescriptorImpl constraintDescriptor = new ConstraintDescriptorImpl( constraintHelper, - config.getLocation().getMember(), + config.getLocation().getConstrainable(), config.createAnnotationDescriptor(), - config.getElementType(), + config.getLocation().getKind(), getConstraintType() ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstructorConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstructorConstraintMappingContextImpl.java index 7f9683a57a..f062f38ab0 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstructorConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ConstructorConstraintMappingContextImpl.java @@ -6,9 +6,8 @@ */ package org.hibernate.validator.internal.cfg.context; -import java.lang.reflect.Constructor; - import org.hibernate.validator.cfg.context.ConstructorConstraintMappingContext; +import org.hibernate.validator.internal.properties.javabean.JavaBeanConstructor; /** * Constraint mapping creational context representing a constructor. @@ -17,7 +16,7 @@ */ class ConstructorConstraintMappingContextImpl extends ExecutableConstraintMappingContextImpl implements ConstructorConstraintMappingContext { - ConstructorConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, Constructor constructor) { + ConstructorConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, JavaBeanConstructor constructor) { super( typeContext, constructor ); } @@ -25,7 +24,7 @@ ConstructorConstraintMappingContextImpl(TypeConstraintMappingContextImpl public ConstructorConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { typeContext.mapping .getAnnotationProcessingOptions() - .ignoreConstraintAnnotationsOnMember( executable, ignoreAnnotations ); + .ignoreConstraintAnnotationsOnMember( callable, ignoreAnnotations ); return this; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ContainerElementConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ContainerElementConstraintMappingContextImpl.java index cf33e40d86..e3eb9f3338 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ContainerElementConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ContainerElementConstraintMappingContextImpl.java @@ -123,6 +123,16 @@ public PropertyConstraintMappingContext property(String property, ElementType el return typeContext.property( property, elementType ); } + @Override + public PropertyConstraintMappingContext field(String property) { + return typeContext.field( property ); + } + + @Override + public PropertyConstraintMappingContext getter(String property) { + return typeContext.getter( property ); + } + @Override public ConstructorConstraintMappingContext constructor(Class... parameterTypes) { return typeContext.constructor( parameterTypes ); @@ -237,9 +247,9 @@ private MetaConstraint asMetaConstraint(ConfiguredCons TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { ConstraintDescriptorImpl constraintDescriptor = new ConstraintDescriptorImpl<>( constraintHelper, - config.getLocation().getMember(), + config.getLocation().getConstrainable(), config.createAnnotationDescriptor(), - config.getElementType(), + config.getLocation().getKind(), getConstraintType() ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/CrossParameterConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/CrossParameterConstraintMappingContextImpl.java index 8cae876274..d1247c09eb 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/CrossParameterConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/CrossParameterConstraintMappingContextImpl.java @@ -32,14 +32,14 @@ final class CrossParameterConstraintMappingContextImpl @Override public CrossParameterConstraintMappingContext constraint(ConstraintDef definition) { - super.addConstraint( ConfiguredConstraint.forCrossParameter( definition, executableContext.getExecutable() ) ); + super.addConstraint( ConfiguredConstraint.forCrossParameter( definition, executableContext.getCallable() ) ); return this; } @Override public CrossParameterConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { mapping.getAnnotationProcessingOptions().ignoreConstraintAnnotationsForCrossParameterConstraint( - executableContext.getExecutable(), ignoreAnnotations + executableContext.getCallable(), ignoreAnnotations ); return this; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ExecutableConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ExecutableConstraintMappingContextImpl.java index 3f2f6d3523..503c284637 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ExecutableConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ExecutableConstraintMappingContextImpl.java @@ -9,7 +9,6 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Executable; import java.util.Collections; import java.util.List; @@ -24,7 +23,7 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; -import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; @@ -41,20 +40,20 @@ abstract class ExecutableConstraintMappingContextImpl { private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); protected final TypeConstraintMappingContextImpl typeContext; - protected final Executable executable; + protected final Callable callable; private final ParameterConstraintMappingContextImpl[] parameterContexts; private ReturnValueConstraintMappingContextImpl returnValueContext; private CrossParameterConstraintMappingContextImpl crossParameterContext; - protected ExecutableConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, Executable executable) { + protected ExecutableConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, Callable callable) { this.typeContext = typeContext; - this.executable = executable; - this.parameterContexts = new ParameterConstraintMappingContextImpl[executable.getParameterTypes().length]; + this.callable = callable; + this.parameterContexts = new ParameterConstraintMappingContextImpl[callable.getParameterTypes().length]; } public ParameterConstraintMappingContext parameter(int index) { - if ( index < 0 || index >= executable.getParameterTypes().length ) { - throw LOG.getInvalidExecutableParameterIndexException( executable, index ); + if ( index < 0 || index >= callable.getParameterTypes().length ) { + throw LOG.getInvalidExecutableParameterIndexException( callable, index ); } ParameterConstraintMappingContextImpl context = parameterContexts[index]; @@ -62,7 +61,7 @@ public ParameterConstraintMappingContext parameter(int index) { if ( context != null ) { throw LOG.getParameterHasAlreadyBeConfiguredViaProgrammaticApiException( typeContext.getBeanClass(), - executable, + callable, index ); } @@ -76,7 +75,7 @@ public CrossParameterConstraintMappingContext crossParameter() { if ( crossParameterContext != null ) { throw LOG.getCrossParameterElementHasAlreadyBeConfiguredViaProgrammaticApiException( typeContext.getBeanClass(), - executable + callable ); } @@ -88,7 +87,7 @@ public ReturnValueConstraintMappingContext returnValue() { if ( returnValueContext != null ) { throw LOG.getReturnValueHasAlreadyBeConfiguredViaProgrammaticApiException( typeContext.getBeanClass(), - executable + callable ); } @@ -96,8 +95,8 @@ public ReturnValueConstraintMappingContext returnValue() { return returnValueContext; } - public Executable getExecutable() { - return executable; + public Callable getCallable() { + return callable; } public TypeConstraintMappingContextImpl getTypeContext() { @@ -108,7 +107,7 @@ public ConstrainedElement build(ConstraintHelper constraintHelper, TypeResolutio ValueExtractorManager valueExtractorManager) { return new ConstrainedExecutable( ConfigurationSource.API, - executable, + callable, getParameters( constraintHelper, typeResolutionHelper, valueExtractorManager ), crossParameterContext != null ? crossParameterContext.getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ) : Collections.>emptySet(), returnValueContext != null ? returnValueContext.getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ) : Collections.>emptySet(), @@ -130,8 +129,8 @@ private List getParameters(ConstraintHelper constraintHelp constrainedParameters.add( new ConstrainedParameter( ConfigurationSource.API, - executable, - ReflectionHelper.typeOf( executable, i ), + callable, + callable.getParameterGenericType( i ), i ) ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/FieldConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/FieldConstraintMappingContextImpl.java new file mode 100644 index 0000000000..bc77618fb6 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/FieldConstraintMappingContextImpl.java @@ -0,0 +1,58 @@ +/* + * 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.cfg.context; + +import org.hibernate.validator.cfg.ConstraintDef; +import org.hibernate.validator.cfg.context.PropertyConstraintMappingContext; +import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; +import org.hibernate.validator.internal.metadata.core.ConstraintHelper; +import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.metadata.raw.ConstrainedField; +import org.hibernate.validator.internal.properties.javabean.JavaBeanField; +import org.hibernate.validator.internal.util.TypeResolutionHelper; + +/** + * An implementation of {@link AbstractPropertyConstraintMappingContextImpl} for a field property. + * Represents a constraint mapping creational context which allows to configure the constraints + * for one of the bean's field properties. + * + * @author Marko Bekhta + */ +final class FieldConstraintMappingContextImpl extends AbstractPropertyConstraintMappingContextImpl { + + FieldConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, JavaBeanField javaBeanField) { + super( typeContext, javaBeanField, ConstraintLocation.forField( javaBeanField ) ); + } + + @Override + public PropertyConstraintMappingContext constraint(ConstraintDef definition) { + super.addConstraint( + ConfiguredConstraint.forField( + definition, getProperty() + ) + ); + return this; + } + + ConstrainedElement build(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { + return new ConstrainedField( + ConfigurationSource.API, + getProperty(), + getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), + getTypeArgumentConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), + getCascadingMetaDataBuilder() + ); + } + + @Override + protected ConstraintType getConstraintType() { + return ConstraintType.GENERIC; + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/GetterConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/GetterConstraintMappingContextImpl.java new file mode 100644 index 0000000000..e78c2534cc --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/GetterConstraintMappingContextImpl.java @@ -0,0 +1,52 @@ +/* + * 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.cfg.context; + +import org.hibernate.validator.cfg.ConstraintDef; +import org.hibernate.validator.cfg.context.PropertyConstraintMappingContext; +import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; +import org.hibernate.validator.internal.metadata.core.ConstraintHelper; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; +import org.hibernate.validator.internal.util.TypeResolutionHelper; + +/** + * An implementation of {@link AbstractPropertyConstraintMappingContextImpl} for a getter property. + * Represents a constraint mapping creational context which allows to configure the constraints + * for one of the bean's getter properties. + * + * @author Marko Bekhta + */ +final class GetterConstraintMappingContextImpl extends AbstractPropertyConstraintMappingContextImpl { + + GetterConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, JavaBeanGetter javaBeanGetter) { + super( typeContext, javaBeanGetter, ConstraintLocation.forGetter( javaBeanGetter ) ); + } + + @Override + public PropertyConstraintMappingContext constraint(ConstraintDef definition) { + super.addConstraint( + ConfiguredConstraint.forGetter( + definition, getProperty() + ) + ); + return this; + } + + ConstrainedElement build(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { + return new ConstrainedExecutable( + ConfigurationSource.API, + getProperty(), + getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), + getTypeArgumentConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), + getCascadingMetaDataBuilder() + ); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/MethodConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/MethodConstraintMappingContextImpl.java index 6ff256f34a..7e8ae93bbe 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/MethodConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/MethodConstraintMappingContextImpl.java @@ -6,9 +6,8 @@ */ package org.hibernate.validator.internal.cfg.context; -import java.lang.reflect.Method; - import org.hibernate.validator.cfg.context.MethodConstraintMappingContext; +import org.hibernate.validator.internal.properties.javabean.JavaBeanMethod; /** * Constraint mapping creational context representing a method. @@ -17,15 +16,15 @@ */ class MethodConstraintMappingContextImpl extends ExecutableConstraintMappingContextImpl implements MethodConstraintMappingContext { - MethodConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, Method method) { - super( typeContext, method ); + MethodConstraintMappingContextImpl(TypeConstraintMappingContextImpl typeContext, JavaBeanMethod callable) { + super( typeContext, callable ); } @Override public MethodConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { typeContext.mapping .getAnnotationProcessingOptions() - .ignoreConstraintAnnotationsOnMember( executable, ignoreAnnotations ); + .ignoreConstraintAnnotationsOnMember( callable, ignoreAnnotations ); return this; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ParameterConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ParameterConstraintMappingContextImpl.java index 5009fc76cd..314b23f1c7 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ParameterConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ParameterConstraintMappingContextImpl.java @@ -21,7 +21,6 @@ import org.hibernate.validator.internal.metadata.location.ConstraintLocation; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; -import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; /** @@ -41,7 +40,7 @@ final class ParameterConstraintMappingContextImpl ParameterConstraintMappingContextImpl(ExecutableConstraintMappingContextImpl executableContext, int parameterIndex) { super( executableContext.getTypeContext().getConstraintMapping(), - executableContext.executable.getGenericParameterTypes()[parameterIndex] + executableContext.callable.getParameterGenericType( parameterIndex ) ); this.executableContext = executableContext; @@ -58,7 +57,7 @@ public ParameterConstraintMappingContext constraint(ConstraintDef definiti super.addConstraint( ConfiguredConstraint.forParameter( definition, - executableContext.getExecutable(), + executableContext.getCallable(), parameterIndex ) ); @@ -68,7 +67,7 @@ public ParameterConstraintMappingContext constraint(ConstraintDef definiti @Override public ParameterConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { mapping.getAnnotationProcessingOptions().ignoreConstraintAnnotationsOnParameter( - executableContext.getExecutable(), + executableContext.getCallable(), parameterIndex, ignoreAnnotations ); @@ -105,7 +104,7 @@ public ContainerElementConstraintMappingContext containerElementType() { return super.containerElement( this, executableContext.getTypeContext(), - ConstraintLocation.forParameter( executableContext.getExecutable(), parameterIndex ) + ConstraintLocation.forParameter( executableContext.getCallable(), parameterIndex ) ); } @@ -114,7 +113,7 @@ public ContainerElementConstraintMappingContext containerElementType(int index, return super.containerElement( this, executableContext.getTypeContext(), - ConstraintLocation.forParameter( executableContext.getExecutable(), parameterIndex ), + ConstraintLocation.forParameter( executableContext.getCallable(), parameterIndex ), index, nestedIndexes ); @@ -122,11 +121,11 @@ public ContainerElementConstraintMappingContext containerElementType(int index, public ConstrainedParameter build(ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { - Type parameterType = ReflectionHelper.typeOf( executableContext.getExecutable(), parameterIndex ); + Type parameterType = executableContext.getCallable().getParameterGenericType( parameterIndex ); return new ConstrainedParameter( ConfigurationSource.API, - executableContext.getExecutable(), + executableContext.getCallable(), parameterType, parameterIndex, getConstraints( constraintHelper, typeResolutionHelper, valueExtractorManager ), diff --git a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ReturnValueConstraintMappingContextImpl.java b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ReturnValueConstraintMappingContextImpl.java index df930c5ce6..7b98e80ea1 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ReturnValueConstraintMappingContextImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/cfg/context/ReturnValueConstraintMappingContextImpl.java @@ -15,7 +15,6 @@ import org.hibernate.validator.cfg.context.ReturnValueConstraintMappingContext; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; -import org.hibernate.validator.internal.util.ReflectionHelper; /** * Constraint mapping creational context which allows to configure the constraints for one method return value. @@ -31,10 +30,7 @@ final class ReturnValueConstraintMappingContextImpl private final ExecutableConstraintMappingContextImpl executableContext; ReturnValueConstraintMappingContextImpl(ExecutableConstraintMappingContextImpl executableContext) { - super( - executableContext.getTypeContext().getConstraintMapping(), - ReflectionHelper.typeOf( executableContext.getExecutable() ) - ); + super( executableContext.getTypeContext().getConstraintMapping(), executableContext.getCallable().getType() ); this.executableContext = executableContext; } @@ -45,14 +41,14 @@ protected ReturnValueConstraintMappingContext getThis() { @Override public ReturnValueConstraintMappingContext constraint(ConstraintDef definition) { - super.addConstraint( ConfiguredConstraint.forExecutable( definition, executableContext.getExecutable() ) ); + super.addConstraint( ConfiguredConstraint.forExecutable( definition, executableContext.getCallable() ) ); return this; } @Override public ReturnValueConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) { mapping.getAnnotationProcessingOptions().ignoreConstraintAnnotationsForReturnValue( - executableContext.getExecutable(), ignoreAnnotations + executableContext.getCallable(), ignoreAnnotations ); return this; } @@ -80,7 +76,7 @@ public ConstructorConstraintMappingContext constructor(Class... parameterType @Override public ContainerElementConstraintMappingContext containerElementType() { return super.containerElement( - this, executableContext.getTypeContext(), ConstraintLocation.forReturnValue( executableContext.getExecutable() ) + this, executableContext.getTypeContext(), ConstraintLocation.forReturnValue( executableContext.getCallable() ) ); } @@ -89,7 +85,7 @@ public ContainerElementConstraintMappingContext containerElementType(int index, return super.containerElement( this, executableContext.getTypeContext(), - ConstraintLocation.forReturnValue( executableContext.getExecutable() ), + ConstraintLocation.forReturnValue( executableContext.getCallable() ), index, nestedIndexes ); 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 63275fc6aa..2b5c270ad4 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 @@ -12,7 +12,7 @@ import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; -import java.lang.reflect.Member; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -33,6 +33,12 @@ import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.properties.Constrainable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanConstructor; +import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanField; +import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; +import org.hibernate.validator.internal.properties.javabean.JavaBeanMethod; import org.hibernate.validator.internal.util.Contracts; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ReflectionHelper; @@ -63,8 +69,8 @@ public final class TypeConstraintMappingContextImpl extends ConstraintMapping private final Class beanClass; private final Set executableContexts = newHashSet(); - private final Set propertyContexts = newHashSet(); - private final Set configuredMembers = newHashSet(); + private final Set> propertyContexts = newHashSet(); + private final Set configuredMembers = newHashSet(); private List> defaultGroupSequence; private Class> defaultGroupSequenceProviderClass; @@ -112,28 +118,56 @@ public TypeConstraintMappingContext defaultGroupSequenceProviderClass(Class... parameterT throw LOG.getBeanDoesNotContainMethodException( beanClass, name, parameterTypes ); } - if ( configuredMembers.contains( method ) ) { - throw LOG.getMethodHasAlreadyBeConfiguredViaProgrammaticApiException( + JavaBeanMethod javaBeanMethod = JavaBeanExecutable.of( method ); + + if ( configuredMembers.contains( javaBeanMethod ) ) { + throw LOG.getMethodHasAlreadyBeenConfiguredViaProgrammaticApiException( beanClass, ExecutableHelper.getExecutableAsString( name, parameterTypes ) ); } - MethodConstraintMappingContextImpl context = new MethodConstraintMappingContextImpl( this, method ); - configuredMembers.add( method ); + MethodConstraintMappingContextImpl context = new MethodConstraintMappingContextImpl( this, javaBeanMethod ); + configuredMembers.add( javaBeanMethod ); executableContexts.add( context ); return context; @@ -173,7 +209,9 @@ public ConstructorConstraintMappingContext constructor(Class... parameterType ); } - if ( configuredMembers.contains( constructor ) ) { + JavaBeanConstructor javaBeanConstructor = new JavaBeanConstructor( constructor ); + + if ( configuredMembers.contains( javaBeanConstructor ) ) { throw LOG.getConstructorHasAlreadyBeConfiguredViaProgrammaticApiException( beanClass, ExecutableHelper.getExecutableAsString( beanClass.getSimpleName(), parameterTypes ) @@ -182,9 +220,9 @@ public ConstructorConstraintMappingContext constructor(Class... parameterType ConstructorConstraintMappingContextImpl context = new ConstructorConstraintMappingContextImpl( this, - constructor + javaBeanConstructor ); - configuredMembers.add( constructor ); + configuredMembers.add( javaBeanConstructor ); executableContexts.add( context ); return context; @@ -220,7 +258,7 @@ private Set buildConstraintElements(ConstraintHelper constra } //properties - for ( PropertyConstraintMappingContextImpl propertyContext : propertyContexts ) { + for ( AbstractPropertyConstraintMappingContextImpl propertyContext : propertyContexts ) { elements.add( propertyContext.build( constraintHelper, typeResolutionHelper, valueExtractorManager ) ); } @@ -245,40 +283,25 @@ protected ConstraintType getConstraintType() { return ConstraintType.GENERIC; } - /** - * Returns the member with the given name and type. - * - * @param clazz The class from which to retrieve the member. Cannot be {@code null}. - * @param property The property name without "is", "get" or "has". Cannot be {@code null} or empty. - * @param elementType The element type. Either {@code ElementType.FIELD} or {@code ElementType METHOD}. - * - * @return the member which matching the name and type or {@code null} if no such member exists. - */ - private Member getMember(Class clazz, String property, ElementType elementType) { + private JavaBeanField getFieldProperty(Class clazz, String property) { Contracts.assertNotNull( clazz, MESSAGES.classCannotBeNull() ); - if ( property == null || property.length() == 0 ) { - throw LOG.getPropertyNameCannotBeNullOrEmptyException(); - } + Field field = run( GetDeclaredField.action( clazz, property ) ); + return field == null ? null : new JavaBeanField( field ); + } - if ( !( ElementType.FIELD.equals( elementType ) || ElementType.METHOD.equals( elementType ) ) ) { - throw LOG.getElementTypeHasToBeFieldOrMethodException(); - } + private JavaBeanGetter getGetterProperty(Class clazz, String property) { + Contracts.assertNotNull( clazz, MESSAGES.classCannotBeNull() ); - Member member = null; - if ( ElementType.FIELD.equals( elementType ) ) { - member = run( GetDeclaredField.action( clazz, property ) ); - } - else { - String methodName = property.substring( 0, 1 ).toUpperCase( Locale.ROOT ) + property.substring( 1 ); - for ( String prefix : ReflectionHelper.PROPERTY_ACCESSOR_PREFIXES ) { - member = run( GetMethod.action( clazz, prefix + methodName ) ); - if ( member != null ) { - break; - } + Method method = null; + String methodName = property.substring( 0, 1 ).toUpperCase( Locale.ROOT ) + property.substring( 1 ); + for ( String prefix : ReflectionHelper.PROPERTY_ACCESSOR_PREFIXES ) { + method = run( GetMethod.action( clazz, prefix + methodName ) ); + if ( method != null ) { + break; } } - return member; + return method == null ? null : new JavaBeanGetter( method ); } /** diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/ConstraintViolationImpl.java b/engine/src/main/java/org/hibernate/validator/internal/engine/ConstraintViolationImpl.java index eecdd5fbbd..69aa6d1619 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/ConstraintViolationImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/ConstraintViolationImpl.java @@ -7,7 +7,6 @@ package org.hibernate.validator.internal.engine; import java.io.Serializable; -import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandles; import java.util.Map; @@ -39,24 +38,22 @@ public class ConstraintViolationImpl implements HibernateConstraintViolation< private final Map messageParameters; private final Map expressionVariables; private final Class rootBeanClass; - private final ElementType elementType; private final Object[] executableParameters; private final Object executableReturnValue; private final Object dynamicPayload; private final int hashCode; public static ConstraintViolation forBeanValidation(String messageTemplate, - Map messageParameters, - Map expressionVariables, - String interpolatedMessage, - Class rootBeanClass, - T rootBean, - Object leafBeanInstance, - Object value, - Path propertyPath, - ConstraintDescriptor constraintDescriptor, - ElementType elementType, - Object dynamicPayload) { + Map messageParameters, + Map expressionVariables, + String interpolatedMessage, + Class rootBeanClass, + T rootBean, + Object leafBeanInstance, + Object value, + Path propertyPath, + ConstraintDescriptor constraintDescriptor, + Object dynamicPayload) { return new ConstraintViolationImpl<>( messageTemplate, messageParameters, @@ -68,7 +65,6 @@ public static ConstraintViolation forBeanValidation(String messageTemplat value, propertyPath, constraintDescriptor, - elementType, null, null, dynamicPayload @@ -76,18 +72,17 @@ public static ConstraintViolation forBeanValidation(String messageTemplat } public static ConstraintViolation forParameterValidation(String messageTemplate, - Map messageParameters, - Map expressionVariables, - String interpolatedMessage, - Class rootBeanClass, - T rootBean, - Object leafBeanInstance, - Object value, - Path propertyPath, - ConstraintDescriptor constraintDescriptor, - ElementType elementType, - Object[] executableParameters, - Object dynamicPayload) { + Map messageParameters, + Map expressionVariables, + String interpolatedMessage, + Class rootBeanClass, + T rootBean, + Object leafBeanInstance, + Object value, + Path propertyPath, + ConstraintDescriptor constraintDescriptor, + Object[] executableParameters, + Object dynamicPayload) { return new ConstraintViolationImpl<>( messageTemplate, messageParameters, @@ -99,7 +94,6 @@ public static ConstraintViolation forParameterValidation(String messageTe value, propertyPath, constraintDescriptor, - elementType, executableParameters, null, dynamicPayload @@ -107,18 +101,17 @@ public static ConstraintViolation forParameterValidation(String messageTe } public static ConstraintViolation forReturnValueValidation(String messageTemplate, - Map messageParameters, - Map expressionVariables, - String interpolatedMessage, - Class rootBeanClass, - T rootBean, - Object leafBeanInstance, - Object value, - Path propertyPath, - ConstraintDescriptor constraintDescriptor, - ElementType elementType, - Object executableReturnValue, - Object dynamicPayload) { + Map messageParameters, + Map expressionVariables, + String interpolatedMessage, + Class rootBeanClass, + T rootBean, + Object leafBeanInstance, + Object value, + Path propertyPath, + ConstraintDescriptor constraintDescriptor, + Object executableReturnValue, + Object dynamicPayload) { return new ConstraintViolationImpl<>( messageTemplate, messageParameters, @@ -130,7 +123,6 @@ public static ConstraintViolation forReturnValueValidation(String message value, propertyPath, constraintDescriptor, - elementType, null, executableReturnValue, dynamicPayload @@ -147,7 +139,6 @@ private ConstraintViolationImpl(String messageTemplate, Object value, Path propertyPath, ConstraintDescriptor constraintDescriptor, - ElementType elementType, Object[] executableParameters, Object executableReturnValue, Object dynamicPayload) { @@ -161,7 +152,6 @@ private ConstraintViolationImpl(String messageTemplate, this.leafBeanInstance = leafBeanInstance; this.constraintDescriptor = constraintDescriptor; this.rootBeanClass = rootBeanClass; - this.elementType = elementType; this.executableParameters = executableParameters; this.executableReturnValue = executableReturnValue; this.dynamicPayload = dynamicPayload; @@ -296,10 +286,6 @@ public boolean equals(Object o) { if ( constraintDescriptor != null ? !constraintDescriptor.equals( that.constraintDescriptor ) : that.constraintDescriptor != null ) { return false; } - if ( elementType != null ? !elementType.equals( that.elementType ) : that.elementType != null ) { - return false; - } - return true; } @@ -331,7 +317,6 @@ private int createHashCode() { result = 31 * result + System.identityHashCode( value ); result = 31 * result + ( constraintDescriptor != null ? constraintDescriptor.hashCode() : 0 ); result = 31 * result + ( messageTemplate != null ? messageTemplate.hashCode() : 0 ); - result = 31 * result + ( elementType != null ? elementType.hashCode() : 0 ); return result; } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java b/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java index 202c758875..9bbe13193e 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java @@ -8,7 +8,6 @@ import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES; -import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -63,6 +62,7 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.facets.Cascadable; import org.hibernate.validator.internal.metadata.facets.Validatable; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.Contracts; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ReflectionHelper; @@ -552,8 +552,8 @@ private void validateCascadedConstraints(BaseBeanValidationContext validation for ( Cascadable cascadable : validatable.getCascadables() ) { valueContext.appendNode( cascadable ); - ElementType elementType = cascadable.getElementType(); - if ( isCascadeRequired( validationContext, valueContext.getCurrentBean(), valueContext.getPropertyPath(), elementType ) ) { + if ( isCascadeRequired( validationContext, valueContext.getCurrentBean(), valueContext.getPropertyPath(), + cascadable.getConstraintLocationKind() ) ) { Object value = getCascadableValue( validationContext, valueContext.getCurrentBean(), cascadable ); CascadingMetaData cascadingMetaData = cascadable.getCascadingMetaData(); @@ -1283,12 +1283,13 @@ private boolean isValidationRequired(BaseBeanValidationContext validationCont validationContext, valueContext.getCurrentBean(), valueContext.getPropertyPath(), - metaConstraint.getElementType() + metaConstraint.getConstraintLocationKind() ); } - private boolean isReachable(BaseBeanValidationContext validationContext, Object traversableObject, PathImpl path, ElementType type) { - if ( needToCallTraversableResolver( path, type ) ) { + private boolean isReachable(BaseBeanValidationContext validationContext, Object traversableObject, PathImpl path, + ConstraintLocationKind constraintLocationKind) { + if ( needToCallTraversableResolver( path, constraintLocationKind ) ) { return true; } @@ -1299,7 +1300,7 @@ private boolean isReachable(BaseBeanValidationContext validationContext, Obje path.getLeafNode(), validationContext.getRootBeanClass(), pathToObject, - type + constraintLocationKind.getElementType() ); } catch (RuntimeException e) { @@ -1307,23 +1308,24 @@ private boolean isReachable(BaseBeanValidationContext validationContext, Obje } } - private boolean needToCallTraversableResolver(PathImpl path, ElementType type) { + private boolean needToCallTraversableResolver(PathImpl path, ConstraintLocationKind constraintLocationKind) { // as the TraversableResolver interface is designed right now it does not make sense to call it when // there is no traversable object hosting the property to be accessed. For this reason we don't call the resolver // for class level constraints (ElementType.TYPE) or top level method parameters or return values. // see also BV expert group discussion - http://lists.jboss.org/pipermail/beanvalidation-dev/2013-January/000722.html - return isClassLevelConstraint( type ) + return isClassLevelConstraint( constraintLocationKind ) || isCrossParameterValidation( path ) || isParameterValidation( path ) || isReturnValueValidation( path ); } - private boolean isCascadeRequired(BaseBeanValidationContext validationContext, Object traversableObject, PathImpl path, ElementType type) { - if ( needToCallTraversableResolver( path, type ) ) { + private boolean isCascadeRequired(BaseBeanValidationContext validationContext, Object traversableObject, PathImpl path, + ConstraintLocationKind constraintLocationKind) { + if ( needToCallTraversableResolver( path, constraintLocationKind ) ) { return true; } - boolean isReachable = isReachable( validationContext, traversableObject, path, type ); + boolean isReachable = isReachable( validationContext, traversableObject, path, constraintLocationKind ); if ( !isReachable ) { return false; } @@ -1335,7 +1337,7 @@ private boolean isCascadeRequired(BaseBeanValidationContext validationContext path.getLeafNode(), validationContext.getRootBeanClass(), pathToObject, - type + constraintLocationKind.getElementType() ); } catch (RuntimeException e) { @@ -1343,8 +1345,8 @@ private boolean isCascadeRequired(BaseBeanValidationContext validationContext } } - private boolean isClassLevelConstraint(ElementType type) { - return ElementType.TYPE.equals( type ); + private boolean isClassLevelConstraint(ConstraintLocationKind constraintLocationKind) { + return ConstraintLocationKind.TYPE.equals( constraintLocationKind ); } private boolean isCrossParameterValidation(PathImpl path) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/ValueContext.java b/engine/src/main/java/org/hibernate/validator/internal/engine/ValueContext.java index 88ba7f7d35..024b5419ec 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/ValueContext.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/ValueContext.java @@ -6,7 +6,6 @@ */ package org.hibernate.validator.internal.engine; -import java.lang.annotation.ElementType; import java.lang.reflect.TypeVariable; import javax.validation.groups.Default; @@ -19,6 +18,7 @@ import org.hibernate.validator.internal.metadata.facets.Cascadable; import org.hibernate.validator.internal.metadata.facets.Validatable; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeVariables; @@ -67,9 +67,9 @@ public class ValueContext { private final Validatable currentValidatable; /** - * The {@code ElementType} the constraint was defined on + * The {@code ConstraintLocationKind} the constraint was defined on */ - private ElementType elementType; + private ConstraintLocationKind constraintLocationKind; public static ValueContext getLocalExecutionContext(BeanMetaDataManager beanMetaDataManager, ExecutableParameterNameProvider parameterNameProvider, T value, Validatable validatable, PathImpl propertyPath) { @@ -199,12 +199,12 @@ public final boolean validatingDefault() { return getCurrentGroup() != null && getCurrentGroup().getName().equals( Default.class.getName() ); } - public final ElementType getElementType() { - return elementType; + public final ConstraintLocationKind getConstraintLocationKind() { + return constraintLocationKind; } - public final void setElementType(ElementType elementType) { - this.elementType = elementType; + public final void setConstraintLocationKind(ConstraintLocationKind constraintLocationKind) { + this.constraintLocationKind = constraintLocationKind; } public final ValueState getCurrentValueState() { @@ -225,7 +225,7 @@ public String toString() { sb.append( ", propertyPath=" ).append( propertyPath ); sb.append( ", currentGroup=" ).append( currentGroup ); sb.append( ", currentValue=" ).append( currentValue ); - sb.append( ", elementType=" ).append( elementType ); + sb.append( ", constraintLocationKind=" ).append( constraintLocationKind ); sb.append( '}' ); return sb.toString(); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/BeanValidationContext.java b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/BeanValidationContext.java index 3aaee06783..3a6afdb698 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/BeanValidationContext.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/BeanValidationContext.java @@ -61,7 +61,6 @@ protected ConstraintViolation createConstraintViolation( localContext.getCurrentValidatedValue(), propertyPath, constraintDescriptor, - localContext.getElementType(), constraintViolationCreationContext.getDynamicPayload() ); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ParameterExecutableValidationContext.java b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ParameterExecutableValidationContext.java index c581746598..c7eaa48498 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ParameterExecutableValidationContext.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ParameterExecutableValidationContext.java @@ -129,7 +129,6 @@ protected ConstraintViolation createConstraintViolation( valueContext.getCurrentValidatedValue(), propertyPath, constraintDescriptor, - valueContext.getElementType(), executableParameters, constraintViolationCreationContext.getDynamicPayload() ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/PropertyValidationContext.java b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/PropertyValidationContext.java index 1a2a1d8a1f..ba79e43a76 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/PropertyValidationContext.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/PropertyValidationContext.java @@ -23,8 +23,7 @@ import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData; import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; -import org.hibernate.validator.internal.metadata.location.FieldConstraintLocation; -import org.hibernate.validator.internal.metadata.location.GetterConstraintLocation; +import org.hibernate.validator.internal.metadata.location.AbstractPropertyConstraintLocation; import org.hibernate.validator.internal.metadata.location.TypeArgumentConstraintLocation; /** @@ -72,11 +71,8 @@ private String getPropertyName(ConstraintLocation location) { location = ( (TypeArgumentConstraintLocation) location ).getOuterDelegate(); } - if ( location instanceof FieldConstraintLocation ) { - return ( (FieldConstraintLocation) location ).getPropertyName(); - } - else if ( location instanceof GetterConstraintLocation ) { - return ( (GetterConstraintLocation) location ).getPropertyName(); + if ( location instanceof AbstractPropertyConstraintLocation ) { + return ( (AbstractPropertyConstraintLocation) location ).getPropertyName(); } return null; @@ -98,7 +94,6 @@ protected ConstraintViolation createConstraintViolation( localContext.getCurrentValidatedValue(), propertyPath, constraintDescriptor, - localContext.getElementType(), constraintViolationCreationContext.getDynamicPayload() ); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ReturnValueExecutableValidationContext.java b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ReturnValueExecutableValidationContext.java index 1c2455fa4d..da619edddc 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ReturnValueExecutableValidationContext.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/ReturnValueExecutableValidationContext.java @@ -101,7 +101,6 @@ protected ConstraintViolation createConstraintViolation(String messageTemplat valueContext.getCurrentValidatedValue(), propertyPath, constraintDescriptor, - valueContext.getElementType(), executableReturnValue, constraintViolationCreationContext.getDynamicPayload() ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/AbstractPropertyCascadable.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/AbstractPropertyCascadable.java new file mode 100644 index 0000000000..1cb08aea79 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/AbstractPropertyCascadable.java @@ -0,0 +1,94 @@ +/* + * 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.metadata.aggregated; + +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; +import org.hibernate.validator.internal.metadata.facets.Cascadable; +import org.hibernate.validator.internal.properties.Field; +import org.hibernate.validator.internal.properties.Getter; +import org.hibernate.validator.internal.properties.Property; +import org.hibernate.validator.internal.properties.PropertyAccessor; + +/** + * A {@link Cascadable} backed by a property of a Java bean. + * + * @author Gunnar Morling + * @author Marko Bekhta + */ +public abstract class AbstractPropertyCascadable implements Cascadable { + + private final T property; + private final PropertyAccessor propertyAccessor; + private final Type cascadableType; + private final CascadingMetaData cascadingMetaData; + + AbstractPropertyCascadable(T property, CascadingMetaData cascadingMetaData) { + this.property = property; + this.propertyAccessor = property.createAccessor(); + this.cascadableType = property.getType(); + this.cascadingMetaData = cascadingMetaData; + } + + @Override + public Type getCascadableType() { + return cascadableType; + } + + @Override + public Object getValue(Object parent) { + return propertyAccessor.getValueFrom( parent ); + } + + @Override + public void appendTo(PathImpl path) { + path.addPropertyNode( property.getPropertyName() ); + } + + @Override + public CascadingMetaData getCascadingMetaData() { + return cascadingMetaData; + } + + public abstract static class AbstractBuilder implements Cascadable.Builder { + + private final ValueExtractorManager valueExtractorManager; + private final T property; + private CascadingMetaDataBuilder cascadingMetaDataBuilder; + + protected AbstractBuilder(ValueExtractorManager valueExtractorManager, T property, CascadingMetaDataBuilder cascadingMetaDataBuilder) { + this.valueExtractorManager = valueExtractorManager; + this.property = property; + this.cascadingMetaDataBuilder = cascadingMetaDataBuilder; + } + + @Override + public void mergeCascadingMetaData(CascadingMetaDataBuilder cascadingMetaData) { + this.cascadingMetaDataBuilder = this.cascadingMetaDataBuilder.merge( cascadingMetaData ); + } + + @Override + public Cascadable build() { + return create( property, cascadingMetaDataBuilder.build( valueExtractorManager, property ) ); + } + + protected abstract Cascadable create(T property, CascadingMetaData build); + + public static Cascadable.Builder builder(ValueExtractorManager valueExtractorManager, Property property, + CascadingMetaDataBuilder cascadingMetaDataBuilder) { + if ( property instanceof Field ) { + return new FieldCascadable.Builder( valueExtractorManager, (Field) property, cascadingMetaDataBuilder ); + } + else if ( property instanceof Getter ) { + return new GetterCascadable.Builder( valueExtractorManager, (Getter) property, cascadingMetaDataBuilder ); + } + throw new IllegalStateException( "It should be either a field or a getter." ); + } + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/BeanMetaDataImpl.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/BeanMetaDataImpl.java index dedbfd2128..059d34ba6c 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/BeanMetaDataImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/BeanMetaDataImpl.java @@ -9,15 +9,13 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; -import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandles; import java.lang.reflect.Executable; -import java.lang.reflect.Member; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -41,13 +39,15 @@ import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.descriptor.ExecutableDescriptorImpl; import org.hibernate.validator.internal.metadata.facets.Cascadable; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; 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.metadata.raw.ConstrainedElement.ConstrainedElementKind; import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; @@ -197,6 +197,7 @@ public BeanMetaDataImpl(Class beanClass, Set tmpUnconstrainedExecutables = newHashSet(); boolean hasConstraints = false; + Set> allMetaConstraints = newHashSet(); for ( ConstraintMetaData constraintMetaData : constraintMetaDataSet ) { boolean elementHasConstraints = constraintMetaData.isCascading() || constraintMetaData.isConstrained(); @@ -205,6 +206,9 @@ public BeanMetaDataImpl(Class beanClass, if ( constraintMetaData.getKind() == ElementKind.PROPERTY ) { propertyMetaDataSet.add( (PropertyMetaData) constraintMetaData ); } + else if ( constraintMetaData.getKind() == ElementKind.BEAN ) { + allMetaConstraints.addAll( ( (ClassMetaData) constraintMetaData ).getAllConstraints() ); + } else { ExecutableMetaData executableMetaData = (ExecutableMetaData) constraintMetaData; if ( elementHasConstraints ) { @@ -217,7 +221,6 @@ public BeanMetaDataImpl(Class beanClass, } Set cascadedProperties = newHashSet(); - Set> allMetaConstraints = newHashSet(); for ( PropertyMetaData propertyMetaData : propertyMetaDataSet ) { propertyMetaDataMap.put( propertyMetaData.getName(), propertyMetaData ); @@ -400,7 +403,7 @@ private static BeanDescriptor createBeanDescriptor(Class beanClass, Set> getClassLevelConstraintsAsDescriptors(Set> constraints) { return constraints.stream() - .filter( c -> c.getElementType() == ElementType.TYPE ) + .filter( c -> c.getConstraintLocationKind() == ConstraintLocationKind.TYPE ) .map( MetaConstraint::getDescriptor ) .collect( Collectors.toSet() ); } @@ -697,7 +700,7 @@ private static class BuilderDelegate { private final TypeResolutionHelper typeResolutionHelper; private final ValueExtractorManager valueExtractorManager; private final ExecutableParameterNameProvider parameterNameProvider; - private MetaDataBuilder propertyBuilder; + private MetaDataBuilder metaDataBuilder; private ExecutableMetaData.Builder methodBuilder; private final MethodValidationConfiguration methodValidationConfiguration; private final int hashCode; @@ -724,7 +727,7 @@ public BuilderDelegate( switch ( constrainedElement.getKind() ) { case FIELD: ConstrainedField constrainedField = (ConstrainedField) constrainedElement; - propertyBuilder = new PropertyMetaData.Builder( + metaDataBuilder = new PropertyMetaData.Builder( beanClass, constrainedField, constraintHelper, @@ -734,12 +737,13 @@ public BuilderDelegate( break; case CONSTRUCTOR: case METHOD: + case GETTER: ConstrainedExecutable constrainedExecutable = (ConstrainedExecutable) constrainedElement; - Member member = constrainedExecutable.getExecutable(); + Callable member = constrainedExecutable.getCallable(); // HV-890 Not adding meta-data for private super-type methods to the method meta-data of this bean; // It is not needed and it may conflict with sub-type methods of the same signature - if ( !Modifier.isPrivate( member.getModifiers() ) || beanClass == member.getDeclaringClass() ) { + if ( !member.isPrivate() || beanClass == member.getDeclaringClass() ) { methodBuilder = new ExecutableMetaData.Builder( beanClass, constrainedExecutable, @@ -752,8 +756,8 @@ public BuilderDelegate( ); } - if ( constrainedExecutable.isGetterMethod() ) { - propertyBuilder = new PropertyMetaData.Builder( + if ( constrainedElement.getKind() == ConstrainedElementKind.GETTER ) { + metaDataBuilder = new PropertyMetaData.Builder( beanClass, constrainedExecutable, constraintHelper, @@ -764,7 +768,7 @@ public BuilderDelegate( break; case TYPE: ConstrainedType constrainedType = (ConstrainedType) constrainedElement; - propertyBuilder = new PropertyMetaData.Builder( + metaDataBuilder = new ClassMetaData.Builder( beanClass, constrainedType, constraintHelper, @@ -772,6 +776,9 @@ public BuilderDelegate( valueExtractorManager ); break; + default: + throw new IllegalStateException( + String.format( Locale.ROOT, "Constrained element kind '%1$s' not supported here.", constrainedElement.getKind() ) ); } this.hashCode = buildHashCode(); @@ -785,10 +792,10 @@ public boolean add(ConstrainedElement constrainedElement) { added = true; } - if ( propertyBuilder != null && propertyBuilder.accepts( constrainedElement ) ) { - propertyBuilder.add( constrainedElement ); + if ( metaDataBuilder != null && metaDataBuilder.accepts( constrainedElement ) ) { + metaDataBuilder.add( constrainedElement ); - if ( !added && constrainedElement.getKind() == ConstrainedElementKind.METHOD && methodBuilder == null ) { + if ( !added && constrainedElement.getKind().isMethod() && methodBuilder == null ) { ConstrainedExecutable constrainedMethod = (ConstrainedExecutable) constrainedElement; methodBuilder = new ExecutableMetaData.Builder( beanClass, @@ -811,8 +818,8 @@ public boolean add(ConstrainedElement constrainedElement) { public Set build() { Set metaDataSet = newHashSet(); - if ( propertyBuilder != null ) { - metaDataSet.add( propertyBuilder.build() ); + if ( metaDataBuilder != null ) { + metaDataSet.add( metaDataBuilder.build() ); } if ( methodBuilder != null ) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ClassMetaData.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ClassMetaData.java new file mode 100644 index 0000000000..b6ea598143 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ClassMetaData.java @@ -0,0 +1,111 @@ +/* + * 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.metadata.aggregated; + +import java.util.List; +import java.util.Set; + +import javax.validation.ElementKind; + +import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; +import org.hibernate.validator.internal.metadata.core.ConstraintHelper; +import org.hibernate.validator.internal.metadata.core.MetaConstraint; +import org.hibernate.validator.internal.metadata.descriptor.ClassDescriptorImpl; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.util.TypeResolutionHelper; + +/** + * Represents the constraint related meta data for a type i.e. class-level + * constraints. + * + * @author Gunnar Morling + * @author Guillaume Smet + * @author Marko Bekhta + */ +public class ClassMetaData extends AbstractConstraintMetaData { + + private ClassMetaData(Class beanClass, + Set> constraints, + Set> containerElementsConstraints) { + super( + beanClass.getSimpleName(), + beanClass, + constraints, + containerElementsConstraints, + false, + !constraints.isEmpty() || !containerElementsConstraints.isEmpty() + ); + } + + @Override + public ClassDescriptorImpl asDescriptor(boolean defaultGroupSequenceRedefined, List> defaultGroupSequence) { + return new ClassDescriptorImpl( + getType(), + asDescriptors( getDirectConstraints() ), + defaultGroupSequenceRedefined, + defaultGroupSequence + ); + } + + @Override + public String toString() { + return "ClassLevelMetaData [type=" + getType() + "]]"; + } + + @Override + public ElementKind getKind() { + return ElementKind.BEAN; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( !super.equals( obj ) ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + return true; + } + + public static class Builder extends MetaDataBuilder { + public Builder(Class beanClass, ConstrainedType constrainedType, ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, + ValueExtractorManager valueExtractorManager) { + super( beanClass, constraintHelper, typeResolutionHelper, valueExtractorManager ); + + add( constrainedType ); + } + + @Override + public boolean accepts(ConstrainedElement constrainedElement) { + return constrainedElement.getKind() == ConstrainedElement.ConstrainedElementKind.TYPE; + } + + @Override + public final void add(ConstrainedElement constrainedElement) { + super.add( constrainedElement ); + } + + @Override + public ClassMetaData build() { + return new ClassMetaData( + getBeanClass(), + adaptOriginsAndImplicitGroups( getDirectConstraints() ), + adaptOriginsAndImplicitGroups( getContainerElementConstraints() ) + ); + } + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ExecutableMetaData.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ExecutableMetaData.java index 46d1aa7050..cd86946d31 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ExecutableMetaData.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ExecutableMetaData.java @@ -10,9 +10,6 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collections; @@ -31,12 +28,13 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.descriptor.ExecutableDescriptorImpl; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; -import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.stereotypes.Immutable; @@ -256,12 +254,11 @@ public static class Builder extends MetaDataBuilder { private final Set signatures = newHashSet(); /** - * Either CONSTRUCTOR or METHOD. + * Either CONSTRUCTOR, METHOD or GETTER. */ - private final ConstrainedElement.ConstrainedElementKind kind; + private final ConstrainedElementKind kind; private final Set constrainedExecutables = newHashSet(); - private Executable executable; - private final boolean isGetterMethod; + private Callable callable; private final Set> crossParameterConstraints = newHashSet(); private final Set rules; private boolean isConstrained = false; @@ -293,9 +290,8 @@ public Builder( this.executableHelper = executableHelper; this.parameterNameProvider = parameterNameProvider; this.kind = constrainedExecutable.getKind(); - this.executable = constrainedExecutable.getExecutable(); + this.callable = constrainedExecutable.getCallable(); this.rules = methodValidationConfiguration.getConfiguredRuleSet(); - this.isGetterMethod = constrainedExecutable.isGetterMethod(); add( constrainedExecutable ); } @@ -306,27 +302,31 @@ public boolean accepts(ConstrainedElement constrainedElement) { return false; } - Executable candidate = ( (ConstrainedExecutable) constrainedElement ).getExecutable(); + Callable candidate = ( (ConstrainedExecutable) constrainedElement ).getCallable(); //are the locations equal (created by different builders) or //does one of the executables override the other one? - return isResolvedToSameMethodInHierarchy( executable, candidate ); + return isResolvedToSameMethodInHierarchy( callable, candidate ); } - private boolean isResolvedToSameMethodInHierarchy(Executable first, Executable other) { - if ( first instanceof Constructor || other instanceof Constructor ) { + private boolean isResolvedToSameMethodInHierarchy(Callable first, Callable other) { + if ( isConstructor( first ) || isConstructor( other ) ) { return first.equals( other ); } - return executableHelper.isResolvedToSameMethodInHierarchy( getBeanClass(), (Method) first, (Method) other ); + return first.isResolvedToSameMethodInHierarchy( executableHelper, getBeanClass(), other ); } - private boolean overrides(Executable first, Executable other) { - if ( first instanceof Constructor || other instanceof Constructor ) { + private boolean overrides(Callable first, Callable other) { + if ( isConstructor( first ) || isConstructor( other ) ) { return false; } - return executableHelper.overrides( (Method) first, (Method) other ); + return executableHelper.overrides( first, other ); + } + + private boolean isConstructor(Callable callable) { + return callable.getConstrainedElementKind() == ConstrainedElementKind.CONSTRUCTOR; } @Override @@ -334,7 +334,7 @@ public final void add(ConstrainedElement constrainedElement) { super.add( constrainedElement ); ConstrainedExecutable constrainedExecutable = (ConstrainedExecutable) constrainedElement; - signatures.add( ExecutableHelper.getSignature( constrainedExecutable.getExecutable() ) ); + signatures.add( constrainedExecutable.getCallable().getSignature() ); constrainedExecutables.add( constrainedExecutable ); isConstrained = isConstrained || constrainedExecutable.isConstrained(); @@ -350,11 +350,11 @@ public final void add(ConstrainedElement constrainedElement) { // keep the "lowest" executable in hierarchy to make sure any type parameters declared on super-types (and // used in overridden methods) are resolved for the specific sub-type we are interested in - if ( executable != null && overrides( - constrainedExecutable.getExecutable(), - executable + if ( callable != null && overrides( + constrainedExecutable.getCallable(), + callable ) ) { - executable = constrainedExecutable.getExecutable(); + callable = constrainedExecutable.getCallable(); } } @@ -365,7 +365,7 @@ public final void add(ConstrainedElement constrainedElement) { * @param executable The executable to merge. */ private void addToExecutablesByDeclaringType(ConstrainedExecutable executable) { - Class beanClass = executable.getExecutable().getDeclaringClass(); + Class beanClass = executable.getCallable().getDeclaringClass(); ConstrainedExecutable mergedExecutable = executablesByDeclaringType.get( beanClass ); if ( mergedExecutable != null ) { @@ -383,19 +383,19 @@ public ExecutableMetaData build() { assertCorrectnessOfConfiguration(); return new ExecutableMetaData( - kind == ConstrainedElement.ConstrainedElementKind.CONSTRUCTOR ? executable.getDeclaringClass().getSimpleName() : executable.getName(), - ReflectionHelper.typeOf( executable ), - executable.getParameterTypes(), - kind == ConstrainedElement.ConstrainedElementKind.CONSTRUCTOR ? ElementKind.CONSTRUCTOR : ElementKind.METHOD, - kind == ConstrainedElement.ConstrainedElementKind.CONSTRUCTOR ? Collections.singleton( ExecutableHelper.getSignature( executable ) ) : + kind == ConstrainedElementKind.CONSTRUCTOR ? callable.getDeclaringClass().getSimpleName() : callable.getName(), + callable.getType(), + callable.getParameterTypes(), + kind == ConstrainedElementKind.CONSTRUCTOR ? ElementKind.CONSTRUCTOR : ElementKind.METHOD, + kind == ConstrainedElementKind.CONSTRUCTOR ? Collections.singleton( callable.getSignature() ) : CollectionHelper.toImmutableSet( signatures ), adaptOriginsAndImplicitGroups( getDirectConstraints() ), adaptOriginsAndImplicitGroups( getContainerElementConstraints() ), findParameterMetaData(), adaptOriginsAndImplicitGroups( crossParameterConstraints ), - cascadingMetaDataBuilder.build( valueExtractorManager, executable ), + cascadingMetaDataBuilder.build( valueExtractorManager, callable ), isConstrained, - isGetterMethod + kind == ConstrainedElementKind.GETTER ); } @@ -416,7 +416,7 @@ private List findParameterMetaData() { for ( ConstrainedParameter oneParameter : oneExecutable.getAllParameterMetaData() ) { parameterBuilders.add( new ParameterMetaData.Builder( - executable.getDeclaringClass(), + callable.getDeclaringClass(), oneParameter, constraintHelper, typeResolutionHelper, diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/FieldCascadable.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/FieldCascadable.java index 6ca82faea5..c8ebe21304 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/FieldCascadable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/FieldCascadable.java @@ -6,105 +6,37 @@ */ package org.hibernate.validator.internal.metadata.aggregated; -import java.lang.annotation.ElementType; -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.hibernate.validator.HibernateValidatorPermission; -import org.hibernate.validator.internal.engine.path.PathImpl; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; import org.hibernate.validator.internal.metadata.facets.Cascadable; -import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; +import org.hibernate.validator.internal.properties.Field; /** * A {@link Cascadable} backed by a field of a Java bean. * * @author Gunnar Morling + * @author Marko Bekhta */ -public class FieldCascadable implements Cascadable { - - private final Field field; - private final Type cascadableType; - private final CascadingMetaData cascadingMetaData; +public class FieldCascadable extends AbstractPropertyCascadable { FieldCascadable(Field field, CascadingMetaData cascadingMetaData) { - this.field = field; - this.cascadableType = ReflectionHelper.typeOf( field ); - this.cascadingMetaData = cascadingMetaData; - } - - @Override - public ElementType getElementType() { - return ElementType.FIELD; - } - - @Override - public Type getCascadableType() { - return cascadableType; - } - - @Override - public Object getValue(Object parent) { - return ReflectionHelper.getValue( field, parent ); - } - - @Override - public void appendTo(PathImpl path) { - path.addPropertyNode( field.getName() ); + super( field, cascadingMetaData ); } @Override - public CascadingMetaData getCascadingMetaData() { - return cascadingMetaData; + public ConstraintLocationKind getConstraintLocationKind() { + return ConstraintLocationKind.FIELD; } - public static class Builder implements Cascadable.Builder { - - private final ValueExtractorManager valueExtractorManager; - private final Field field; - private CascadingMetaDataBuilder cascadingMetaDataBuilder; + public static class Builder extends AbstractPropertyCascadable.AbstractBuilder { - public Builder(ValueExtractorManager valueExtractorManager, Field field, CascadingMetaDataBuilder cascadingMetaDataBuilder) { - this.valueExtractorManager = valueExtractorManager; - this.field = field; - this.cascadingMetaDataBuilder = cascadingMetaDataBuilder; - } - - @Override - public void mergeCascadingMetaData(CascadingMetaDataBuilder cascadingMetaData) { - this.cascadingMetaDataBuilder = this.cascadingMetaDataBuilder.merge( cascadingMetaData ); + protected Builder(ValueExtractorManager valueExtractorManager, Field field, CascadingMetaDataBuilder cascadingMetaDataBuilder) { + super( valueExtractorManager, field, cascadingMetaDataBuilder ); } @Override - public FieldCascadable build() { - return new FieldCascadable( getAccessible( field ), cascadingMetaDataBuilder.build( valueExtractorManager, field ) ); - } - - /** - * Returns an accessible copy of the given member. - */ - private 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 T run(PrivilegedAction action) { - return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); + protected Cascadable create(Field field, CascadingMetaData cascadingMetaData) { + return new FieldCascadable( field, cascadingMetaData ); } } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/GetterCascadable.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/GetterCascadable.java index 72854cfa39..ab5da7d89f 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/GetterCascadable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/GetterCascadable.java @@ -6,80 +6,37 @@ */ package org.hibernate.validator.internal.metadata.aggregated; -import java.lang.annotation.ElementType; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -import org.hibernate.validator.internal.engine.path.PathImpl; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; import org.hibernate.validator.internal.metadata.facets.Cascadable; -import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; +import org.hibernate.validator.internal.properties.Getter; /** - * A {@link Cascadable} backed by a property getter of a Java bean. + * A {@link Cascadable} backed by a getter of a Java bean. * * @author Gunnar Morling + * @author Marko Bekhta */ -public class GetterCascadable implements Cascadable { - - private final Method method; - private final String propertyName; - private final Type cascadableType; - private final CascadingMetaData cascadingMetaData; - - GetterCascadable(Method method, CascadingMetaData cascadingMetaData) { - this.method = method; - this.propertyName = ReflectionHelper.getPropertyName( method ); - this.cascadableType = ReflectionHelper.typeOf( method ); - this.cascadingMetaData = cascadingMetaData; - } - - @Override - public ElementType getElementType() { - return ElementType.METHOD; - } - - @Override - public Type getCascadableType() { - return cascadableType; - } +public class GetterCascadable extends AbstractPropertyCascadable { - @Override - public Object getValue(Object parent) { - return ReflectionHelper.getValue( method, parent ); - } - - @Override - public void appendTo(PathImpl path) { - path.addPropertyNode( propertyName ); + GetterCascadable(Getter getter, CascadingMetaData cascadingMetaData) { + super( getter, cascadingMetaData ); } @Override - public CascadingMetaData getCascadingMetaData() { - return cascadingMetaData; + public ConstraintLocationKind getConstraintLocationKind() { + return ConstraintLocationKind.GETTER; } - public static class Builder implements Cascadable.Builder { + public static class Builder extends AbstractPropertyCascadable.AbstractBuilder { - private final ValueExtractorManager valueExtractorManager; - private final Method method; - private CascadingMetaDataBuilder cascadingMetaDataBuilder; - - // Note: the method passed here has to be accessible: the caller is responsible for that - public Builder(ValueExtractorManager valueExtractorManager, Method method, CascadingMetaDataBuilder cascadingMetaDataBuilder) { - this.valueExtractorManager = valueExtractorManager; - this.method = method; - this.cascadingMetaDataBuilder = cascadingMetaDataBuilder; - } - - @Override - public void mergeCascadingMetaData(CascadingMetaDataBuilder cascadingMetaData) { - this.cascadingMetaDataBuilder = this.cascadingMetaDataBuilder.merge( cascadingMetaData ); + protected Builder(ValueExtractorManager valueExtractorManager, Getter getter, CascadingMetaDataBuilder cascadingMetaDataBuilder) { + super( valueExtractorManager, getter, cascadingMetaDataBuilder ); } @Override - public GetterCascadable build() { - return new GetterCascadable( method, cascadingMetaDataBuilder.build( valueExtractorManager, method ) ); + protected Cascadable create(Getter getter, CascadingMetaData cascadingMetaData) { + return new GetterCascadable( getter, cascadingMetaData ); } } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/MetaDataBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/MetaDataBuilder.java index 92e7c077be..cecf054f94 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/MetaDataBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/MetaDataBuilder.java @@ -129,9 +129,9 @@ private MetaConstraint adaptOriginAndImplicitGroup(Met ConstraintDescriptorImpl descriptor = new ConstraintDescriptorImpl<>( constraintHelper, - constraint.getLocation().getMember(), + constraint.getLocation().getConstrainable(), constraint.getDescriptor().getAnnotationDescriptor(), - constraint.getElementType(), + constraint.getConstraintLocationKind(), constraintClass.isInterface() ? constraintClass : null, definedIn, constraint.getDescriptor().getConstraintType() diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ParameterMetaData.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ParameterMetaData.java index d175c6e548..839d12f812 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ParameterMetaData.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ParameterMetaData.java @@ -6,8 +6,6 @@ */ package org.hibernate.validator.internal.metadata.aggregated; -import java.lang.annotation.ElementType; -import java.lang.reflect.Executable; import java.lang.reflect.Type; import java.util.List; import java.util.Set; @@ -21,9 +19,11 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.descriptor.ParameterDescriptorImpl; import org.hibernate.validator.internal.metadata.facets.Cascadable; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -64,8 +64,8 @@ public int getIndex() { } @Override - public ElementType getElementType() { - return ElementType.PARAMETER; + public ConstraintLocationKind getConstraintLocationKind() { + return ConstraintLocationKind.PARAMETER; } @Override @@ -112,7 +112,7 @@ public static class Builder extends MetaDataBuilder { private final ExecutableParameterNameProvider parameterNameProvider; private final Type parameterType; private final int parameterIndex; - private Executable executableForNameRetrieval; + private Callable callableForNameRetrieval; private CascadingMetaDataBuilder cascadingMetaDataBuilder; public Builder(Class beanClass, @@ -156,9 +156,9 @@ public void add(ConstrainedElement constrainedElement) { // use this parent class parameter name instead of the more specific one. // Worse case, we are consistent, best case parameters from parents are more meaningful. // See HV-887 and the associated unit test - if ( executableForNameRetrieval == null || - newConstrainedParameter.getExecutable().getDeclaringClass().isAssignableFrom( executableForNameRetrieval.getDeclaringClass() ) ) { - executableForNameRetrieval = newConstrainedParameter.getExecutable(); + if ( callableForNameRetrieval == null || + newConstrainedParameter.getCallable().getDeclaringClass().isAssignableFrom( callableForNameRetrieval.getDeclaringClass() ) ) { + callableForNameRetrieval = newConstrainedParameter.getCallable(); } } @@ -166,11 +166,11 @@ public void add(ConstrainedElement constrainedElement) { public ParameterMetaData build() { return new ParameterMetaData( parameterIndex, - parameterNameProvider.getParameterNames( executableForNameRetrieval ).get( parameterIndex ), + callableForNameRetrieval.getParameterName( parameterNameProvider, parameterIndex ), parameterType, adaptOriginsAndImplicitGroups( getDirectConstraints() ), adaptOriginsAndImplicitGroups( getContainerElementConstraints() ), - cascadingMetaDataBuilder.build( valueExtractorManager, executableForNameRetrieval ) + cascadingMetaDataBuilder.build( valueExtractorManager, callableForNameRetrieval ) ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/PropertyMetaData.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/PropertyMetaData.java index f616e8e923..fffa02635a 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/PropertyMetaData.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/PropertyMetaData.java @@ -6,12 +6,8 @@ */ package org.hibernate.validator.internal.metadata.aggregated; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Type; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; @@ -25,7 +21,6 @@ import javax.validation.ElementKind; -import org.hibernate.validator.HibernateValidatorPermission; import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; @@ -39,11 +34,13 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedField; -import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.properties.Getter; +import org.hibernate.validator.internal.properties.Property; +import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; import org.hibernate.validator.internal.util.CollectionHelper; -import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod; +import org.hibernate.validator.internal.util.logging.Log; +import org.hibernate.validator.internal.util.logging.LoggerFactory; import org.hibernate.validator.internal.util.stereotypes.Immutable; /** @@ -64,6 +61,8 @@ */ public class PropertyMetaData extends AbstractConstraintMetaData { + private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); + @Immutable private final Set cascadables; @@ -71,8 +70,7 @@ private PropertyMetaData(String propertyName, Type type, Set> constraints, Set> containerElementsConstraints, - Set cascadables, - boolean cascadingProperty) { + Set cascadables) { super( propertyName, type, @@ -151,41 +149,29 @@ public boolean equals(Object obj) { public static class Builder extends MetaDataBuilder { private static final EnumSet SUPPORTED_ELEMENT_KINDS = EnumSet.of( - ConstrainedElementKind.TYPE, ConstrainedElementKind.FIELD, - ConstrainedElementKind.METHOD + ConstrainedElementKind.GETTER ); private final String propertyName; - private final Map cascadableBuilders = new HashMap<>(); + private final Map cascadableBuilders = new HashMap<>(); private final Type propertyType; - private boolean cascadingProperty = false; - private Method getterAccessibleMethod; - - public Builder(Class beanClass, ConstrainedField constrainedField, ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, - ValueExtractorManager valueExtractorManager) { - super( beanClass, constraintHelper, typeResolutionHelper, valueExtractorManager ); - this.propertyName = constrainedField.getField().getName(); - this.propertyType = ReflectionHelper.typeOf( constrainedField.getField() ); - add( constrainedField ); - } - - public Builder(Class beanClass, ConstrainedType constrainedType, ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, + public Builder(Class beanClass, ConstrainedField constrainedProperty, ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { super( beanClass, constraintHelper, typeResolutionHelper, valueExtractorManager ); - this.propertyName = null; - this.propertyType = null; - add( constrainedType ); + this.propertyName = constrainedProperty.getField().getName(); + this.propertyType = constrainedProperty.getField().getType(); + add( constrainedProperty ); } public Builder(Class beanClass, ConstrainedExecutable constrainedMethod, ConstraintHelper constraintHelper, TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) { super( beanClass, constraintHelper, typeResolutionHelper, valueExtractorManager ); - this.propertyName = ReflectionHelper.getPropertyName( constrainedMethod.getExecutable() ); - this.propertyType = ReflectionHelper.typeOf( constrainedMethod.getExecutable() ); + this.propertyName = constrainedMethod.getCallable().as( Property.class ).getPropertyName(); + this.propertyType = constrainedMethod.getCallable().getType(); add( constrainedMethod ); } @@ -195,62 +181,59 @@ public boolean accepts(ConstrainedElement constrainedElement) { return false; } - if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD && - !( (ConstrainedExecutable) constrainedElement ).isGetterMethod() ) { - return false; - } - return Objects.equals( getPropertyName( constrainedElement ), propertyName ); } @Override public final void add(ConstrainedElement constrainedElement) { - // if we are in the case of a getter and if we have constraints (either on the annotated object itself or on - // a container element) or cascaded validation, we want to create an accessible version of the getter only once. - if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD && constrainedElement.isConstrained() ) { - getterAccessibleMethod = getAccessible( (Method) ( (ConstrainedExecutable) constrainedElement ).getExecutable() ); - } - super.add( constrainedElement ); - cascadingProperty = cascadingProperty || constrainedElement.getCascadingMetaDataBuilder().isCascading(); - if ( constrainedElement.getCascadingMetaDataBuilder().isMarkedForCascadingOnAnnotatedObjectOrContainerElements() || constrainedElement.getCascadingMetaDataBuilder().hasGroupConversionsOnAnnotatedObjectOrContainerElements() ) { - if ( constrainedElement.getKind() == ConstrainedElementKind.FIELD ) { - Field field = ( (ConstrainedField) constrainedElement ).getField(); - Cascadable.Builder builder = cascadableBuilders.get( field ); - if ( builder == null ) { - builder = new FieldCascadable.Builder( valueExtractorManager, field, constrainedElement.getCascadingMetaDataBuilder() ); - cascadableBuilders.put( field, builder ); + Property property = getConstrainableFromConstrainedElement( constrainedElement ); + + Cascadable.Builder builder = cascadableBuilders.get( property ); + if ( builder == null ) { + builder = AbstractPropertyCascadable.AbstractBuilder.builder( valueExtractorManager, property, + constrainedElement.getCascadingMetaDataBuilder() ); + cascadableBuilders.put( property, builder ); + } + else { + builder.mergeCascadingMetaData( constrainedElement.getCascadingMetaDataBuilder() ); + } + } + } + + private Property getConstrainableFromConstrainedElement(ConstrainedElement constrainedElement) { + switch ( constrainedElement.getKind() ) { + case FIELD: + if ( constrainedElement instanceof ConstrainedField ) { + return ( (ConstrainedField) constrainedElement ).getField(); } else { - builder.mergeCascadingMetaData( constrainedElement.getCascadingMetaDataBuilder() ); + throw LOG.getUnexpectedConstraintElementType( ConstrainedField.class, constrainedElement.getClass() ); } - } - else if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD ) { - Method method = (Method) ( (ConstrainedExecutable) constrainedElement ).getExecutable(); - Cascadable.Builder builder = cascadableBuilders.get( method ); - - if ( builder == null ) { - builder = new GetterCascadable.Builder( valueExtractorManager, getterAccessibleMethod, constrainedElement.getCascadingMetaDataBuilder() ); - cascadableBuilders.put( method, builder ); + case GETTER: + if ( constrainedElement instanceof ConstrainedExecutable ) { + return ( (ConstrainedExecutable) constrainedElement ).getCallable().as( Getter.class ); } else { - builder.mergeCascadingMetaData( constrainedElement.getCascadingMetaDataBuilder() ); + throw LOG.getUnexpectedConstraintElementType( ConstrainedExecutable.class, constrainedElement.getClass() ); } - } + default: + throw LOG.getUnsupportedConstraintElementType( constrainedElement.getKind() ); } } @Override protected Set> adaptConstraints(ConstrainedElement constrainedElement, Set> constraints) { - if ( constraints.isEmpty() || constrainedElement.getKind() != ConstrainedElementKind.METHOD ) { + if ( constraints.isEmpty() || constrainedElement.getKind() != ConstrainedElementKind.GETTER ) { return constraints; } - ConstraintLocation getterConstraintLocation = ConstraintLocation.forGetter( getterAccessibleMethod ); + ConstraintLocation getterConstraintLocation = ConstraintLocation + .forGetter( ( (ConstrainedExecutable) constrainedElement ).getCallable().as( JavaBeanGetter.class ) ); // convert return value locations into getter locations for usage within this meta-data return constraints.stream() @@ -262,7 +245,7 @@ private MetaConstraint withGetterLocation(ConstraintLocation getterConstraint ConstraintLocation converted = null; // fast track if it's a regular constraint - if ( !(constraint.getLocation() instanceof TypeArgumentConstraintLocation) ) { + if ( !( constraint.getLocation() instanceof TypeArgumentConstraintLocation ) ) { // Change the constraint location to a GetterConstraintLocation if it is not already one if ( constraint.getLocation() instanceof GetterConstraintLocation ) { converted = constraint.getLocation(); @@ -313,33 +296,15 @@ private MetaConstraint withGetterLocation(ConstraintLocation getterConstraint private String getPropertyName(ConstrainedElement constrainedElement) { if ( constrainedElement.getKind() == ConstrainedElementKind.FIELD ) { - return ReflectionHelper.getPropertyName( ( (ConstrainedField) constrainedElement ).getField() ); + return ( (ConstrainedField) constrainedElement ).getField().getPropertyName(); } - else if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD ) { - return ReflectionHelper.getPropertyName( ( (ConstrainedExecutable) constrainedElement ).getExecutable() ); + else if ( constrainedElement.getKind() == ConstrainedElementKind.GETTER ) { + return ( (ConstrainedExecutable) constrainedElement ).getCallable().as( Property.class ).getPropertyName(); } return null; } - /** - * Returns an accessible copy of the given member. - */ - private Method getAccessible(Method original) { - SecurityManager sm = System.getSecurityManager(); - if ( sm != null ) { - sm.checkPermission( HibernateValidatorPermission.ACCESS_PRIVATE_MEMBERS ); - } - - Class clazz = original.getDeclaringClass(); - - return run( GetDeclaredMethod.andMakeAccessible( clazz, original.getName() ) ); - } - - private T run(PrivilegedAction action) { - return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); - } - @Override public PropertyMetaData build() { Set cascadables = cascadableBuilders.values() @@ -352,8 +317,7 @@ public PropertyMetaData build() { propertyType, adaptOriginsAndImplicitGroups( getDirectConstraints() ), adaptOriginsAndImplicitGroups( getContainerElementConstraints() ), - cascadables, - cascadingProperty + cascadables ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ReturnValueMetaData.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ReturnValueMetaData.java index 6e9062b131..aac44bf57f 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ReturnValueMetaData.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/ReturnValueMetaData.java @@ -6,7 +6,6 @@ */ package org.hibernate.validator.internal.metadata.aggregated; -import java.lang.annotation.ElementType; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; @@ -20,6 +19,7 @@ import org.hibernate.validator.internal.metadata.descriptor.ReturnValueDescriptorImpl; import org.hibernate.validator.internal.metadata.facets.Cascadable; import org.hibernate.validator.internal.metadata.facets.Validatable; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.stereotypes.Immutable; /** @@ -67,8 +67,8 @@ public boolean hasCascadables() { } @Override - public ElementType getElementType() { - return ElementType.METHOD; + public ConstraintLocationKind getConstraintLocationKind() { + return ConstraintLocationKind.METHOD; } @Override diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/MethodConfigurationRule.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/MethodConfigurationRule.java index c7d1831283..7b4eeffd7e 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/MethodConfigurationRule.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/MethodConfigurationRule.java @@ -54,8 +54,8 @@ protected boolean isStrictSubType(Class clazz, Class otherClazz) { * {@code otherExecutable}, {@code false} otherwise */ protected boolean isDefinedOnSubType(ConstrainedExecutable executable, ConstrainedExecutable otherExecutable) { - Class clazz = executable.getExecutable().getDeclaringClass(); - Class otherClazz = otherExecutable.getExecutable().getDeclaringClass(); + Class clazz = executable.getCallable().getDeclaringClass(); + Class otherClazz = otherExecutable.getCallable().getDeclaringClass(); return isStrictSubType( clazz, otherClazz ); } @@ -71,8 +71,8 @@ protected boolean isDefinedOnSubType(ConstrainedExecutable executable, Constrain * {@code otherExecutable}, {@code false} otherwise */ protected boolean isDefinedOnParallelType(ConstrainedExecutable executable, ConstrainedExecutable otherExecutable) { - Class clazz = executable.getExecutable().getDeclaringClass(); - Class otherClazz = otherExecutable.getExecutable().getDeclaringClass(); + Class clazz = executable.getCallable().getDeclaringClass(); + Class otherClazz = otherExecutable.getCallable().getDeclaringClass(); return !( clazz.isAssignableFrom( otherClazz ) || otherClazz.isAssignableFrom( clazz ) ); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/OverridingMethodMustNotAlterParameterConstraints.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/OverridingMethodMustNotAlterParameterConstraints.java index 2e402c25bb..2b88e5e953 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/OverridingMethodMustNotAlterParameterConstraints.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/OverridingMethodMustNotAlterParameterConstraints.java @@ -22,8 +22,8 @@ public void apply(ConstrainedExecutable method, ConstrainedExecutable otherMetho otherMethod.hasParameterConstraints() && !method.isEquallyParameterConstrained( otherMethod ) ) { throw LOG.getParameterConfigurationAlteredInSubTypeException( - method.getExecutable(), - otherMethod.getExecutable() + method.getCallable(), + otherMethod.getCallable() ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue.java index 4546d1278e..69cc7debfb 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue.java @@ -25,8 +25,8 @@ public void apply(ConstrainedExecutable method, ConstrainedExecutable otherMetho if ( isDefinedOnParallelType( method, otherMethod ) && isCascaded && hasGroupConversions ) { throw LOG.getMethodsFromParallelTypesMustNotDefineGroupConversionsForCascadedReturnValueException( - method.getExecutable(), - otherMethod.getExecutable() + method.getCallable(), + otherMethod.getCallable() ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineParameterConstraints.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineParameterConstraints.java index 2023e3ab2d..12abf849b4 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineParameterConstraints.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ParallelMethodsMustNotDefineParameterConstraints.java @@ -21,8 +21,8 @@ public void apply(ConstrainedExecutable method, ConstrainedExecutable otherMetho if ( isDefinedOnParallelType( method, otherMethod ) && ( method.hasParameterConstraints() || otherMethod.hasParameterConstraints() ) ) { throw LOG.getParameterConstraintsDefinedInMethodsFromParallelTypesException( - method.getExecutable(), - otherMethod.getExecutable() + method.getCallable(), + otherMethod.getCallable() ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine.java index 7bac3875e9..f29b70cc94 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine.java @@ -22,8 +22,8 @@ public void apply(ConstrainedExecutable method, ConstrainedExecutable otherMetho otherMethod.getCascadingMetaDataBuilder().isMarkedForCascadingOnAnnotatedObjectOrContainerElements() && ( isDefinedOnSubType( method, otherMethod ) || isDefinedOnSubType( otherMethod, method ) ) ) { throw LOG.getMethodReturnValueMustNotBeMarkedMoreThanOnceForCascadedValidationException( - method.getExecutable(), - otherMethod.getExecutable() + method.getCallable(), + otherMethod.getCallable() ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/VoidMethodsMustNotBeReturnValueConstrained.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/VoidMethodsMustNotBeReturnValueConstrained.java index 3344bd0515..15600a1876 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/VoidMethodsMustNotBeReturnValueConstrained.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/aggregated/rule/VoidMethodsMustNotBeReturnValueConstrained.java @@ -6,8 +6,6 @@ */ package org.hibernate.validator.internal.metadata.aggregated.rule; -import java.lang.reflect.Method; - import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; /** @@ -20,11 +18,10 @@ public class VoidMethodsMustNotBeReturnValueConstrained extends MethodConfigurat @Override public void apply(ConstrainedExecutable executable, ConstrainedExecutable otherExecutable) { - if ( ( executable.getExecutable() instanceof Method ) && - ( (Method) executable.getExecutable() ).getReturnType() == void.class && + if ( !executable.getCallable().hasReturnValue() && ( !executable.getConstraints().isEmpty() || executable.getCascadingMetaDataBuilder().isMarkedForCascadingOnAnnotatedObjectOrContainerElements() ) ) { - throw LOG.getVoidMethodsMustNotBeConstrainedException( executable.getExecutable() ); + throw LOG.getVoidMethodsMustNotBeConstrainedException( executable.getCallable() ); } } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptions.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptions.java index 5e80ed6b4b..dfbc674ff8 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptions.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptions.java @@ -6,7 +6,7 @@ */ package org.hibernate.validator.internal.metadata.core; -import java.lang.reflect.Member; +import org.hibernate.validator.internal.properties.Constrainable; /** * An {@code AnnotationProcessingOptions} instance keeps track of annotations which should be ignored as configuration source. @@ -18,13 +18,13 @@ public interface AnnotationProcessingOptions { boolean areClassLevelConstraintsIgnoredFor(Class clazz); - boolean areMemberConstraintsIgnoredFor(Member member); + boolean areMemberConstraintsIgnoredFor(Constrainable constrainable); - boolean areReturnValueConstraintsIgnoredFor(Member member); + boolean areReturnValueConstraintsIgnoredFor(Constrainable constrainable); - boolean areCrossParameterConstraintsIgnoredFor(Member member); + boolean areCrossParameterConstraintsIgnoredFor(Constrainable constrainable); - boolean areParameterConstraintsIgnoredFor(Member member, int index); + boolean areParameterConstraintsIgnoredFor(Constrainable constrainable, int index); void merge(AnnotationProcessingOptions annotationProcessingOptions); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptionsImpl.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptionsImpl.java index 11bc7d6ccf..b0746a0bdd 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptionsImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/AnnotationProcessingOptionsImpl.java @@ -6,15 +6,15 @@ */ package org.hibernate.validator.internal.metadata.core; +import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; + import java.lang.invoke.MethodHandles; -import java.lang.reflect.Member; import java.util.Map; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; -import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; - /** * An {@code AnnotationProcessingOptions} instance keeps track of annotations which should be ignored as configuration source. * The main validation source for Bean Validation is annotation and alternate configuration sources use this class @@ -40,17 +40,17 @@ public class AnnotationProcessingOptionsImpl implements AnnotationProcessingOpti /** * Keeps track of explicitly excluded members (fields and properties). */ - private final Map annotationIgnoredForMembers = newHashMap(); + private final Map annotationIgnoredForMembers = newHashMap(); /** * Keeps track of explicitly excluded return value constraints for methods/constructors. */ - private final Map annotationIgnoresForReturnValues = newHashMap(); + private final Map annotationIgnoresForReturnValues = newHashMap(); /** * Keeps track of explicitly excluded cross parameter constraints for methods/constructors. */ - private final Map annotationIgnoresForCrossParameter = newHashMap(); + private final Map annotationIgnoresForCrossParameter = newHashMap(); /** * Keeps track whether the 'ignore-annotations' flag is set on a method/constructor parameter @@ -58,10 +58,10 @@ public class AnnotationProcessingOptionsImpl implements AnnotationProcessingOpti private final Map annotationIgnoresForMethodParameter = newHashMap(); @Override - public boolean areMemberConstraintsIgnoredFor(Member member) { - Class clazz = member.getDeclaringClass(); - if ( annotationIgnoredForMembers.containsKey( member ) ) { - return annotationIgnoredForMembers.get( member ); + public boolean areMemberConstraintsIgnoredFor(Constrainable constrainable) { + Class clazz = constrainable.getDeclaringClass(); + if ( annotationIgnoredForMembers.containsKey( constrainable ) ) { + return annotationIgnoredForMembers.get( constrainable ); } else { return areAllConstraintAnnotationsIgnoredFor( clazz ); @@ -69,33 +69,33 @@ public boolean areMemberConstraintsIgnoredFor(Member member) { } @Override - public boolean areReturnValueConstraintsIgnoredFor(Member member) { - if ( annotationIgnoresForReturnValues.containsKey( member ) ) { - return annotationIgnoresForReturnValues.get( member ); + public boolean areReturnValueConstraintsIgnoredFor(Constrainable constrainable) { + if ( annotationIgnoresForReturnValues.containsKey( constrainable ) ) { + return annotationIgnoresForReturnValues.get( constrainable ); } else { - return areMemberConstraintsIgnoredFor( member ); + return areMemberConstraintsIgnoredFor( constrainable ); } } @Override - public boolean areCrossParameterConstraintsIgnoredFor(Member member) { - if ( annotationIgnoresForCrossParameter.containsKey( member ) ) { - return annotationIgnoresForCrossParameter.get( member ); + public boolean areCrossParameterConstraintsIgnoredFor(Constrainable constrainable) { + if ( annotationIgnoresForCrossParameter.containsKey( constrainable ) ) { + return annotationIgnoresForCrossParameter.get( constrainable ); } else { - return areMemberConstraintsIgnoredFor( member ); + return areMemberConstraintsIgnoredFor( constrainable ); } } @Override - public boolean areParameterConstraintsIgnoredFor(Member member, int index) { - ExecutableParameterKey key = new ExecutableParameterKey( member, index ); + public boolean areParameterConstraintsIgnoredFor(Constrainable constrainable, int index) { + ExecutableParameterKey key = new ExecutableParameterKey( constrainable, index ); if ( annotationIgnoresForMethodParameter.containsKey( key ) ) { return annotationIgnoresForMethodParameter.get( key ); } else { - return areMemberConstraintsIgnoredFor( member ); + return areMemberConstraintsIgnoredFor( constrainable ); } } @@ -138,19 +138,19 @@ public void ignoreAnnotationConstraintForClass(Class clazz, Boolean b) { } } - public void ignoreConstraintAnnotationsOnMember(Member member, Boolean b) { + public void ignoreConstraintAnnotationsOnMember(Constrainable member, Boolean b) { annotationIgnoredForMembers.put( member, b ); } - public void ignoreConstraintAnnotationsForReturnValue(Member member, Boolean b) { + public void ignoreConstraintAnnotationsForReturnValue(Constrainable member, Boolean b) { annotationIgnoresForReturnValues.put( member, b ); } - public void ignoreConstraintAnnotationsForCrossParameterConstraint(Member member, Boolean b) { + public void ignoreConstraintAnnotationsForCrossParameterConstraint(Constrainable member, Boolean b) { annotationIgnoresForCrossParameter.put( member, b ); } - public void ignoreConstraintAnnotationsOnParameter(Member member, int index, Boolean b) { + public void ignoreConstraintAnnotationsOnParameter(Constrainable member, int index, Boolean b) { ExecutableParameterKey key = new ExecutableParameterKey( member, index ); annotationIgnoresForMethodParameter.put( key, b ); } @@ -164,11 +164,11 @@ private boolean areAllConstraintAnnotationsIgnoredFor(Class clazz) { } public class ExecutableParameterKey { - private final Member member; + private final Constrainable constrainable; private final int index; - public ExecutableParameterKey(Member member, int index) { - this.member = member; + public ExecutableParameterKey(Constrainable constrainable, int index) { + this.constrainable = constrainable; this.index = index; } @@ -186,7 +186,7 @@ public boolean equals(Object o) { if ( index != that.index ) { return false; } - if ( member != null ? !member.equals( that.member ) : that.member != null ) { + if ( constrainable != null ? !constrainable.equals( that.constrainable ) : that.constrainable != null ) { return false; } @@ -195,7 +195,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = member != null ? member.hashCode() : 0; + int result = constrainable != null ? constrainable.hashCode() : 0; result = 31 * result + index; return result; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/MetaConstraint.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/MetaConstraint.java index a08f40a6b9..de3a33005a 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/core/MetaConstraint.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/core/MetaConstraint.java @@ -7,7 +7,6 @@ package org.hibernate.validator.internal.metadata.core; import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.List; @@ -23,6 +22,7 @@ import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.StringHelper; import org.hibernate.validator.internal.util.stereotypes.Immutable; @@ -100,8 +100,8 @@ public final ConstraintDescriptorImpl getDescriptor() { return constraintTree.getDescriptor(); } - public final ElementType getElementType() { - return constraintTree.getDescriptor().getElementType(); + public final ConstraintLocationKind getConstraintLocationKind() { + return constraintTree.getDescriptor().getConstraintLocationKind(); } public boolean validateConstraint(ValidationContext validationContext, ValueContext valueContext) { @@ -123,7 +123,7 @@ public boolean validateConstraint(ValidationContext validationContext, ValueC } private boolean doValidateConstraint(ValidationContext executionContext, ValueContext valueContext) { - valueContext.setElementType( getElementType() ); + valueContext.setConstraintLocationKind( getConstraintLocationKind() ); boolean validationResult = constraintTree.validateConstraints( executionContext, valueContext ); return validationResult; diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ClassDescriptorImpl.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ClassDescriptorImpl.java new file mode 100644 index 0000000000..0d1f0017b4 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ClassDescriptorImpl.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.metadata.descriptor; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Set; + +import javax.validation.metadata.ElementDescriptor; + +/** + * Describes a validated type class-level constraints. + * + * @author Marko Bekhta + */ +public class ClassDescriptorImpl extends ElementDescriptorImpl implements ElementDescriptor { + + public ClassDescriptorImpl(Type beanType, + Set> constraints, + boolean defaultGroupSequenceRedefined, + List> defaultGroupSequence) { + super( beanType, constraints, defaultGroupSequenceRedefined, defaultGroupSequence ); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( getClass().getSimpleName() ); + sb.append( "{beanType=" ).append( getElementClass() ); + sb.append( '}' ); + return sb.toString(); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ConstraintDescriptorImpl.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ConstraintDescriptorImpl.java index 094c6e54b2..372e45dc44 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ConstraintDescriptorImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ConstraintDescriptorImpl.java @@ -12,15 +12,10 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Member; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -49,6 +44,10 @@ import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorDescriptor; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.ConstraintOrigin; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; +import org.hibernate.validator.internal.properties.Property; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.StringHelper; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; @@ -130,10 +129,10 @@ public class ConstraintDescriptorImpl implements Constrain private final boolean isReportAsSingleInvalidConstraint; /** - * Describes on which level ({@code TYPE}, {@code METHOD}, {@code FIELD}) the constraint was + * Describes on which level ({@code TYPE}, {@code METHOD}, {@code FIELD}...) the constraint was * defined on. */ - private final ElementType elementType; + private final ConstraintLocationKind constraintLocationKind; /** * The origin of the constraint. Defined on the actual root class or somewhere in the class hierarchy @@ -164,14 +163,14 @@ public class ConstraintDescriptorImpl implements Constrain private final int hashCode; public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, - Member member, + Constrainable constrainable, ConstraintAnnotationDescriptor annotationDescriptor, - ElementType type, + ConstraintLocationKind constraintLocationKind, Class implicitGroup, ConstraintOrigin definedOn, ConstraintType externalConstraintType) { this.annotationDescriptor = annotationDescriptor; - this.elementType = type; + this.constraintLocationKind = constraintLocationKind; this.definedOn = definedOn; this.isReportAsSingleInvalidConstraint = annotationDescriptor.getType().isAnnotationPresent( ReportAsSingleViolation.class @@ -182,7 +181,7 @@ public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, this.groups = buildGroupSet( annotationDescriptor, implicitGroup ); this.payloads = buildPayloadSet( annotationDescriptor ); - this.valueUnwrapping = determineValueUnwrapping( this.payloads, member, annotationDescriptor.getType() ); + this.valueUnwrapping = determineValueUnwrapping( this.payloads, constrainable, annotationDescriptor.getType() ); this.validationAppliesTo = determineValidationAppliesTo( annotationDescriptor ); @@ -206,13 +205,12 @@ public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, this.constraintType = determineConstraintType( annotationDescriptor.getType(), - member, - type, + constrainable, !genericValidatorDescriptors.isEmpty(), !crossParameterValidatorDescriptors.isEmpty(), externalConstraintType ); - this.composingConstraints = parseComposingConstraints( constraintHelper, member, constraintType ); + this.composingConstraints = parseComposingConstraints( constraintHelper, constrainable, constraintType ); this.compositionType = parseCompositionType( constraintHelper ); validateComposingConstraintTypes(); @@ -227,18 +225,18 @@ public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, } public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, - Member member, + Constrainable constrainable, ConstraintAnnotationDescriptor annotationDescriptor, - ElementType type) { - this( constraintHelper, member, annotationDescriptor, type, null, ConstraintOrigin.DEFINED_LOCALLY, null ); + ConstraintLocationKind constraintLocationKind) { + this( constraintHelper, constrainable, annotationDescriptor, constraintLocationKind, null, ConstraintOrigin.DEFINED_LOCALLY, null ); } public ConstraintDescriptorImpl(ConstraintHelper constraintHelper, - Member member, + Constrainable constrainable, ConstraintAnnotationDescriptor annotationDescriptor, - ElementType type, + ConstraintLocationKind constraintLocationKind, ConstraintType constraintType) { - this( constraintHelper, member, annotationDescriptor, type, null, ConstraintOrigin.DEFINED_LOCALLY, constraintType ); + this( constraintHelper, constrainable, annotationDescriptor, constraintLocationKind, null, ConstraintOrigin.DEFINED_LOCALLY, constraintType ); } public ConstraintAnnotationDescriptor getAnnotationDescriptor() { @@ -314,8 +312,8 @@ public boolean isReportAsSingleViolation() { return isReportAsSingleInvalidConstraint; } - public ElementType getElementType() { - return elementType; + public ConstraintLocationKind getConstraintLocationKind() { + return constraintLocationKind; } public ConstraintOrigin getDefinedOn() { @@ -362,7 +360,7 @@ public String toString() { sb.append( ", payloads=" ).append( payloads ); sb.append( ", hasComposingConstraints=" ).append( composingConstraints.isEmpty() ); sb.append( ", isReportAsSingleInvalidConstraint=" ).append( isReportAsSingleInvalidConstraint ); - sb.append( ", elementType=" ).append( elementType ); + sb.append( ", constraintLocationKind=" ).append( constraintLocationKind ); sb.append( ", definedOn=" ).append( definedOn ); sb.append( ", groups=" ).append( groups ); sb.append( ", attributes=" ).append( annotationDescriptor.getAttributes() ); @@ -389,8 +387,7 @@ public String toString() { * specify the target explicitly). * * - * @param member The annotated member - * @param elementType The type of the annotated element + * @param constrainable The annotated member * @param hasGenericValidators Whether the constraint has at least one generic validator or * not * @param hasCrossParameterValidator Whether the constraint has a cross-parameter validator @@ -400,14 +397,13 @@ public String toString() { * @return The type of this constraint */ private ConstraintType determineConstraintType(Class constraintAnnotationType, - Member member, - ElementType elementType, + Constrainable constrainable, boolean hasGenericValidators, boolean hasCrossParameterValidator, ConstraintType externalConstraintType) { ConstraintTarget constraintTarget = validationAppliesTo; ConstraintType constraintType = null; - boolean isExecutable = isExecutable( elementType ); + boolean isExecutable = constraintLocationKind.isExecutable(); //target explicitly set to RETURN_VALUE if ( constraintTarget == ConstraintTarget.RETURN_VALUE ) { @@ -453,9 +449,10 @@ else if ( constraintAnnotationType.isAnnotationPresent( SupportedValidationTarge } //try to derive from existence of parameters/return value - else { - boolean hasParameters = hasParameters( member ); - boolean hasReturnValue = hasReturnValue( member ); + //hence look only if it is a callable + else if ( constrainable instanceof Callable ) { + boolean hasParameters = constrainable.as( Callable.class ).hasParameters(); + boolean hasReturnValue = constrainable.as( Callable.class ).hasReturnValue(); if ( !hasParameters && hasReturnValue ) { constraintType = ConstraintType.GENERIC; @@ -472,16 +469,16 @@ else if ( hasParameters && !hasReturnValue ) { } if ( constraintType == ConstraintType.CROSS_PARAMETER ) { - validateCrossParameterConstraintType( member, hasCrossParameterValidator ); + validateCrossParameterConstraintType( constrainable, hasCrossParameterValidator ); } return constraintType; } - private static ValidateUnwrappedValue determineValueUnwrapping(Set> payloads, Member member, Class annotationType) { + private static ValidateUnwrappedValue determineValueUnwrapping(Set> payloads, Constrainable constrainable, Class annotationType) { if ( payloads.contains( Unwrapping.Unwrap.class ) ) { if ( payloads.contains( Unwrapping.Skip.class ) ) { - throw LOG.getInvalidUnwrappingConfigurationForConstraintException( member, annotationType ); + throw LOG.getInvalidUnwrappingConfigurationForConstraintException( constrainable, annotationType ); } return ValidateUnwrappedValue.UNWRAP; @@ -498,20 +495,20 @@ private static ConstraintTarget determineValidationAppliesTo(ConstraintAnnotatio return annotationDescriptor.getValidationAppliesTo(); } - private void validateCrossParameterConstraintType(Member member, boolean hasCrossParameterValidator) { + private void validateCrossParameterConstraintType(Constrainable constrainable, boolean hasCrossParameterValidator) { if ( !hasCrossParameterValidator ) { throw LOG.getCrossParameterConstraintHasNoValidatorException( annotationDescriptor.getType() ); } - else if ( member == null ) { + else if ( constrainable == null ) { throw LOG.getCrossParameterConstraintOnClassException( annotationDescriptor.getType() ); } - else if ( member instanceof Field ) { - throw LOG.getCrossParameterConstraintOnFieldException( annotationDescriptor.getType(), member ); + else if ( constrainable instanceof Property ) { + throw LOG.getCrossParameterConstraintOnFieldException( annotationDescriptor.getType(), constrainable ); } - else if ( !hasParameters( member ) ) { + else if ( !constrainable.as( Callable.class ).hasParameters() ) { throw LOG.getCrossParameterConstraintOnMethodWithoutParametersException( annotationDescriptor.getType(), - (Executable) member + constrainable ); } } @@ -533,39 +530,6 @@ private void validateComposingConstraintTypes() { } } - private boolean hasParameters(Member member) { - boolean hasParameters = false; - if ( member instanceof Constructor ) { - Constructor constructor = (Constructor) member; - hasParameters = constructor.getParameterTypes().length > 0; - } - else if ( member instanceof Method ) { - Method method = (Method) member; - hasParameters = method.getParameterTypes().length > 0; - } - return hasParameters; - } - - private boolean hasReturnValue(Member member) { - boolean hasReturnValue; - if ( member instanceof Constructor ) { - hasReturnValue = true; - } - else if ( member instanceof Method ) { - Method method = (Method) member; - hasReturnValue = method.getGenericReturnType() != void.class; - } - else { - // field or type - hasReturnValue = false; - } - return hasReturnValue; - } - - private boolean isExecutable(ElementType elementType) { - return elementType == ElementType.METHOD || elementType == ElementType.CONSTRUCTOR; - } - @SuppressWarnings("unchecked") private static Set> buildPayloadSet(ConstraintAnnotationDescriptor annotationDescriptor) { Set> payloadSet = newHashSet(); @@ -648,7 +612,7 @@ private void ensureAttributeIsOverridable(Method m, OverridesAttribute overrides } } - private Set> parseComposingConstraints(ConstraintHelper constraintHelper, Member member, + private Set> parseComposingConstraints(ConstraintHelper constraintHelper, Constrainable constrainable, ConstraintType constraintType) { Set> composingConstraintsSet = newHashSet(); Map> overrideParameters = parseOverrideParameters(); @@ -669,7 +633,7 @@ private Set> parseComposingConstraints(ConstraintHel ConstraintDescriptorImpl descriptor = createComposingConstraintDescriptor( constraintHelper, - member, + constrainable, overrideParameters, OVERRIDES_PARAMETER_DEFAULT_INDEX, declaredAnnotation, @@ -691,7 +655,7 @@ else if ( constraintHelper.isMultiValueConstraint( declaredAnnotationType ) ) { ConstraintDescriptorImpl descriptor = createComposingConstraintDescriptor( constraintHelper, - member, + constrainable, overrideParameters, index, constraintAnnotation, @@ -727,7 +691,7 @@ private CompositionType parseCompositionType(ConstraintHelper constraintHelper) private ConstraintDescriptorImpl createComposingConstraintDescriptor( ConstraintHelper constraintHelper, - Member member, + Constrainable constrainable, Map> overrideParameters, int index, U constraintAnnotation, @@ -773,7 +737,7 @@ annotationType, run( GetAnnotationAttributes.action( constraintAnnotation ) ) } return new ConstraintDescriptorImpl<>( - constraintHelper, member, annotationDescriptorBuilder.build(), elementType, null, definedOn, constraintType + constraintHelper, constrainable, annotationDescriptorBuilder.build(), constraintLocationKind, null, definedOn, constraintType ); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ElementDescriptorImpl.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ElementDescriptorImpl.java index d80a1972f2..0c865382fa 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ElementDescriptorImpl.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/descriptor/ElementDescriptorImpl.java @@ -142,7 +142,7 @@ public boolean hasConstraints() { private void addMatchingDescriptorsForGroup(Class group, Set> matchingDescriptors) { for ( ConstraintDescriptorImpl descriptor : constraintDescriptors ) { - if ( definedInSet.contains( descriptor.getDefinedOn() ) && elementTypes.contains( descriptor.getElementType() ) + if ( definedInSet.contains( descriptor.getDefinedOn() ) && elementTypes.contains( descriptor.getConstraintLocationKind().getElementType() ) && descriptor.getGroups().contains( group ) ) { matchingDescriptors.add( descriptor ); } @@ -160,7 +160,7 @@ private void findMatchingDescriptors(Set> matchingDescri } else { for ( ConstraintDescriptorImpl descriptor : constraintDescriptors ) { - if ( definedInSet.contains( descriptor.getDefinedOn() ) && elementTypes.contains( descriptor.getElementType() ) ) { + if ( definedInSet.contains( descriptor.getDefinedOn() ) && elementTypes.contains( descriptor.getConstraintLocationKind().getElementType() ) ) { matchingDescriptors.add( descriptor ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/facets/Cascadable.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/facets/Cascadable.java index f63ed55c9b..fd5864a3d2 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/facets/Cascadable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/facets/Cascadable.java @@ -6,12 +6,12 @@ */ package org.hibernate.validator.internal.metadata.facets; -import java.lang.annotation.ElementType; import java.lang.reflect.Type; import org.hibernate.validator.internal.engine.path.PathImpl; import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaData; import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; /** * Provides a unified view on cascadable elements of all kinds, be it properties @@ -24,11 +24,11 @@ public interface Cascadable { /** - * Returns the element type of the cascadable. + * Returns the constraint location kind of the cascadable. * - * @return Returns the element type of the cascadable. + * @return Returns the constraint location kind of the cascadable. */ - ElementType getElementType(); + ConstraintLocationKind getConstraintLocationKind(); /** * Returns the data type of this cascadable, e.g. the type of a bean property or the diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/AbstractPropertyConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/AbstractPropertyConstraintLocation.java new file mode 100644 index 0000000000..3d7e105ea3 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/AbstractPropertyConstraintLocation.java @@ -0,0 +1,92 @@ +/* + * 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.metadata.location; + +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Property; +import org.hibernate.validator.internal.properties.PropertyAccessor; +import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; + +/** + * An abstract property constraint location. + * + * @author Marko Bekhta + * @author Guillaume Smet + */ +public abstract class AbstractPropertyConstraintLocation implements ConstraintLocation { + + /** + * The property the constraint was defined on. + */ + private final T property; + + private final PropertyAccessor propertyAccessor; + + AbstractPropertyConstraintLocation(T property) { + this.property = property; + this.propertyAccessor = property.createAccessor(); + } + + @Override + public Class getDeclaringClass() { + return property.getDeclaringClass(); + } + + @Override + public T getConstrainable() { + return property; + } + + public String getPropertyName() { + return property.getPropertyName(); + } + + @Override + public Type getTypeForValidatorResolution() { + return property.getTypeForValidatorResolution(); + } + + @Override + public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { + path.addPropertyNode( property.getPropertyName() ); + } + + @Override + public Object getValue(Object parent) { + return propertyAccessor.getValueFrom( parent ); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [property=" + property + "]"; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + AbstractPropertyConstraintLocation that = (AbstractPropertyConstraintLocation) o; + + if ( !property.equals( that.property ) ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return property.hashCode(); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/BeanConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/BeanConstraintLocation.java index e8a573f27b..0ff0fd218f 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/BeanConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/BeanConstraintLocation.java @@ -6,10 +6,10 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Member; import java.lang.reflect.Type; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.TypeHelper; @@ -18,6 +18,7 @@ * * @author Hardy Ferentschik * @author Gunnar Morling + * @author Guillaume Smet */ class BeanConstraintLocation implements ConstraintLocation { @@ -47,7 +48,7 @@ public Class getDeclaringClass() { } @Override - public Member getMember() { + public Constrainable getConstrainable() { return null; } @@ -66,6 +67,11 @@ public Object getValue(Object parent) { return parent; } + @Override + public ConstraintLocationKind getKind() { + return ConstraintLocationKind.TYPE; + } + @Override public String toString() { return "BeanConstraintLocation [declaringClass=" + declaringClass + ", typeForValidatorResolution=" + typeForValidatorResolution + "]"; diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java index 1277f85051..0084fbdde5 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java @@ -6,14 +6,17 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; +import java.lang.annotation.ElementType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.util.Locale; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; +import org.hibernate.validator.internal.properties.Field; +import org.hibernate.validator.internal.properties.Getter; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; /** @@ -43,45 +46,24 @@ static ConstraintLocation forField(Field field) { return new FieldConstraintLocation( field ); } - /** - * Create a new {@link GetterConstraintLocation} for the given getter method. - * - * @param getter The getter method being constrained - * @return A new GetterConstraintLocation - */ - static ConstraintLocation forGetter(Method getter) { - return new GetterConstraintLocation( getter.getDeclaringClass(), getter ); - } - - /** - * Create a new {@link GetterConstraintLocation} for the given declaring class and getter method. - *

- * This provides an alternative to {@link ConstraintLocation#forGetter(Method)} where the given declaring class is usually a sub-class of the - * actual class on which the getter method is declared. This is provided to support XML mapping configurations used to specify constraints on - * subclasses for inherited getter methods. - * - * @param declaringClass The class on which the constraint is defined. - * @param getter The getter method being constrained. - * @return A new GetterConstraintLocation - */ - static ConstraintLocation forGetter(Class declaringClass, Method getter ) { - return new GetterConstraintLocation( declaringClass, getter ); + static ConstraintLocation forGetter(Getter getter) { + return new GetterConstraintLocation( getter ); } static ConstraintLocation forTypeArgument(ConstraintLocation delegate, TypeVariable typeParameter, Type typeOfAnnotatedElement) { return new TypeArgumentConstraintLocation( delegate, typeParameter, typeOfAnnotatedElement ); } - static ConstraintLocation forReturnValue(Executable executable) { - return new ReturnValueConstraintLocation( executable ); + static ConstraintLocation forReturnValue(Callable callable) { + return new ReturnValueConstraintLocation( callable ); } - static ConstraintLocation forCrossParameter(Executable executable) { - return new CrossParameterConstraintLocation( executable ); + static ConstraintLocation forCrossParameter(Callable callable) { + return new CrossParameterConstraintLocation( callable ); } - static ConstraintLocation forParameter(Executable executable, int index) { - return new ParameterConstraintLocation( executable, index ); + static ConstraintLocation forParameter(Callable callable, int index) { + return new ParameterConstraintLocation( callable, index ); } /** @@ -94,7 +76,7 @@ static ConstraintLocation forParameter(Executable executable, int index) { * * @return the member represented by this location. Will be {@code null} when this location represents a type. */ - Member getMember(); + Constrainable getConstrainable(); /** * Returns the type to be used when resolving constraint validators for constraints at this location. Note that this @@ -112,8 +94,61 @@ static ConstraintLocation forParameter(Executable executable, int index) { /** * Obtains the value of this location from the parent. The type of the passed parent depends on the location type, - * e.g. a bean would be passed for a {@link FieldConstraintLocation} or {@link GetterConstraintLocation} but an + * e.g. a bean would be passed for a {@link AbstractPropertyConstraintLocation} but an * object array for a {@link ParameterConstraintLocation}. */ Object getValue(Object parent); + + /** + * Returns the nature of the constraint location. + */ + ConstraintLocationKind getKind(); + + enum ConstraintLocationKind { + TYPE( ElementType.TYPE ), + CONSTRUCTOR( ElementType.CONSTRUCTOR ), + METHOD( ElementType.METHOD ), + PARAMETER( ElementType.PARAMETER ), + FIELD( ElementType.FIELD ), + GETTER( ElementType.METHOD ), + TYPE_USE( ElementType.TYPE_USE ); + + private final ElementType elementType; + + ConstraintLocationKind(ElementType elementType) { + this.elementType = elementType; + } + + public ElementType getElementType() { + return elementType; + } + + public boolean isExecutable() { + return this == CONSTRUCTOR || isMethod(); + } + + public boolean isMethod() { + return this == METHOD || this == GETTER; + } + + public static ConstraintLocationKind of(ConstrainedElementKind constrainedElementKind) { + switch ( constrainedElementKind ) { + case CONSTRUCTOR: + return ConstraintLocationKind.CONSTRUCTOR; + case FIELD: + return ConstraintLocationKind.FIELD; + case METHOD: + return ConstraintLocationKind.METHOD; + case PARAMETER: + return ConstraintLocationKind.PARAMETER; + case TYPE: + return ConstraintLocationKind.TYPE; + case GETTER: + return ConstraintLocationKind.GETTER; + default: + throw new IllegalArgumentException( + String.format( Locale.ROOT, "Constrained element kind '%1$s' not supported.", constrainedElementKind ) ); + } + } + } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/CrossParameterConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/CrossParameterConstraintLocation.java index 0c127fbb0f..0f36fa5ed7 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/CrossParameterConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/CrossParameterConstraintLocation.java @@ -6,11 +6,11 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Executable; -import java.lang.reflect.Member; import java.lang.reflect.Type; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; /** @@ -18,23 +18,27 @@ * * @author Hardy Ferentschik * @author Gunnar Morling + * @author Guillaume Smet */ class CrossParameterConstraintLocation implements ConstraintLocation { - private final Executable executable; + private final Callable callable; - CrossParameterConstraintLocation(Executable executable) { - this.executable = executable; + private final ConstraintLocationKind kind; + + CrossParameterConstraintLocation(Callable callable) { + this.callable = callable; + this.kind = ConstraintLocationKind.of( callable.getConstrainedElementKind() ); } @Override public Class getDeclaringClass() { - return executable.getDeclaringClass(); + return callable.getDeclaringClass(); } @Override - public Member getMember() { - return executable; + public Constrainable getConstrainable() { + return callable; } @Override @@ -52,17 +56,19 @@ public Object getValue(Object parent) { return parent; } + @Override + public ConstraintLocationKind getKind() { + return kind; + } + @Override public String toString() { - return "CrossParameterConstraintLocation [executable=" + executable + "]"; + return "CrossParameterConstraintLocation [callable=" + callable + "]"; } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ( ( executable == null ) ? 0 : executable.hashCode() ); - return result; + return callable.hashCode(); } @Override @@ -77,12 +83,7 @@ public boolean equals(Object obj) { return false; } CrossParameterConstraintLocation other = (CrossParameterConstraintLocation) obj; - if ( executable == null ) { - if ( other.executable != null ) { - return false; - } - } - else if ( !executable.equals( other.executable ) ) { + if ( !callable.equals( other.callable ) ) { return false; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FieldConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FieldConstraintLocation.java index 4e8c21f963..d7639c0646 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FieldConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FieldConstraintLocation.java @@ -6,136 +6,21 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Type; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.hibernate.validator.HibernateValidatorPermission; -import org.hibernate.validator.internal.engine.path.PathImpl; -import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; -import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.StringHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField; +import org.hibernate.validator.internal.properties.Field; /** - * Field constraint location. + * Field property constraint location. * - * @author Hardy Ferentschik - * @author Gunnar Morling + * @author Marko Bekhta */ -public class FieldConstraintLocation implements ConstraintLocation { - - /** - * The member the constraint was defined on. - */ - private final Field field; - - private final Field accessibleField; - - /** - * The property name associated with the member. - */ - private final String propertyName; - - /** - * The type to be used for validator resolution for constraints at this location. - */ - private final Type typeForValidatorResolution; - +public class FieldConstraintLocation extends AbstractPropertyConstraintLocation { FieldConstraintLocation(Field field) { - this.field = field; - this.accessibleField = getAccessible( field ); - this.propertyName = ReflectionHelper.getPropertyName( field ); - this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( field ) ); - } - - @Override - public Class getDeclaringClass() { - return field.getDeclaringClass(); - } - - @Override - public Member getMember() { - return field; - } - - public String getPropertyName() { - return propertyName; - } - - @Override - public Type getTypeForValidatorResolution() { - return typeForValidatorResolution; - } - - @Override - public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { - path.addPropertyNode( propertyName ); - } - - @Override - public Object getValue(Object parent) { - return ReflectionHelper.getValue( accessibleField, parent ); - } - - @Override - public String toString() { - return "FieldConstraintLocation [member=" + StringHelper.toShortString( field ) + ", typeForValidatorResolution=" - + StringHelper.toShortString( typeForValidatorResolution ) + "]"; + super( field ); } @Override - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - if ( o == null || getClass() != o.getClass() ) { - return false; - } - - FieldConstraintLocation that = (FieldConstraintLocation) o; - - if ( field != null ? !field.equals( that.field ) : that.field != null ) { - return false; - } - if ( !typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = field != null ? field.hashCode() : 0; - result = 31 * result + typeForValidatorResolution.hashCode(); - return result; - } - - /** - * 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(); + public ConstraintLocationKind getKind() { + return ConstraintLocationKind.FIELD; } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/GetterConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/GetterConstraintLocation.java index 129772a320..2dee31bf03 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/GetterConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/GetterConstraintLocation.java @@ -6,145 +6,21 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.hibernate.validator.HibernateValidatorPermission; -import org.hibernate.validator.internal.engine.path.PathImpl; -import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; -import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.StringHelper; -import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod; +import org.hibernate.validator.internal.properties.Getter; /** - * Getter method constraint location. + * Getter property constraint location. * - * @author Hardy Ferentschik - * @author Gunnar Morling + * @author Marko Bekhta */ -public class GetterConstraintLocation implements ConstraintLocation { - - /** - * The method the constraint was defined on. - */ - private final Method method; - - private final Method accessibleMethod; - - /** - * The property name associated with the method. - */ - private final String propertyName; - - /** - * The type to be used for validator resolution for constraints at this location. - */ - private final Type typeForValidatorResolution; - - /** - * The class of the method for which the constraint was defined. - *

- * It is usually the same as the declaring class of the method itself, except in the XML case when a user could - * declare a constraint for a specific subclass. - */ - private final Class declaringClass; - - - GetterConstraintLocation( Class declaringClass, Method method ) { - this.method = method; - this.accessibleMethod = getAccessible( method ); - this.propertyName = ReflectionHelper.getPropertyName( method ); - this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( method ) ); - this.declaringClass = declaringClass; - } - - @Override - public Class getDeclaringClass() { - return declaringClass; - } - - @Override - public Method getMember() { - return method; - } +public class GetterConstraintLocation extends AbstractPropertyConstraintLocation { - public String getPropertyName() { - return propertyName; + GetterConstraintLocation(Getter getter) { + super( getter ); } @Override - public Type getTypeForValidatorResolution() { - return typeForValidatorResolution; - } - - @Override - public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { - path.addPropertyNode( propertyName ); - } - - @Override - public Object getValue(Object parent) { - return ReflectionHelper.getValue( accessibleMethod, parent ); - } - - @Override - public String toString() { - return "GetterConstraintLocation [method=" + StringHelper.toShortString( method ) + ", typeForValidatorResolution=" - + StringHelper.toShortString( typeForValidatorResolution ) + "]"; - } - - @Override - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - if ( o == null || getClass() != o.getClass() ) { - return false; - } - - GetterConstraintLocation that = (GetterConstraintLocation) o; - - if ( method != null ? !method.equals( that.method ) : that.method != null ) { - return false; - } - if ( !typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = method.hashCode(); - result = 31 * result + typeForValidatorResolution.hashCode(); - return result; - } - - /** - * 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(); + public ConstraintLocationKind getKind() { + return ConstraintLocationKind.GETTER; } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ParameterConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ParameterConstraintLocation.java index 8c816b2299..29392b77ff 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ParameterConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ParameterConstraintLocation.java @@ -6,11 +6,11 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Executable; -import java.lang.reflect.Member; import java.lang.reflect.Type; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.ReflectionHelper; @@ -19,27 +19,30 @@ * * @author Hardy Ferentschik * @author Gunnar Morling + * @author Guillaume Smet */ public class ParameterConstraintLocation implements ConstraintLocation { - private final Executable executable; + private final Callable callable; private final int index; private final Type typeForValidatorResolution; + private final ConstraintLocationKind kind; - ParameterConstraintLocation(Executable executable, int index) { - this.executable = executable; + public ParameterConstraintLocation(Callable callable, int index) { + this.callable = callable; this.index = index; - this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( executable, index ) ); + this.typeForValidatorResolution = ReflectionHelper.boxedType( callable.getParameterGenericType( index ) ); + this.kind = ConstraintLocationKind.of( callable.getConstrainedElementKind() ); } @Override public Class getDeclaringClass() { - return executable.getDeclaringClass(); + return callable.getDeclaringClass(); } @Override - public Member getMember() { - return executable; + public Constrainable getConstrainable() { + return callable; } @Override @@ -53,8 +56,7 @@ public int getIndex() { @Override public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { - String name = parameterNameProvider.getParameterNames( executable ).get( index ); - path.addParameterNode( name, index ); + path.addParameterNode( callable.getParameterName( parameterNameProvider, index ), index ); } @Override @@ -62,17 +64,21 @@ public Object getValue(Object parent) { return ( (Object[]) parent )[index]; } + @Override + public ConstraintLocationKind getKind() { + return kind; + } + @Override public String toString() { - return "ParameterConstraintLocation [executable=" + executable + ", index=" + index - + ", typeForValidatorResolution=" + typeForValidatorResolution + "]"; + return "ParameterConstraintLocation [callable=" + callable + ", index=" + index + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ( ( executable == null ) ? 0 : executable.hashCode() ); + result = prime * result + callable.hashCode(); result = prime * result + index; return result; } @@ -89,12 +95,7 @@ public boolean equals(Object obj) { return false; } ParameterConstraintLocation other = (ParameterConstraintLocation) obj; - if ( executable == null ) { - if ( other.executable != null ) { - return false; - } - } - else if ( !executable.equals( other.executable ) ) { + if ( !callable.equals( other.callable ) ) { return false; } if ( index != other.index ) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ReturnValueConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ReturnValueConstraintLocation.java index b6ac18e2ca..6ee7b3f924 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ReturnValueConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ReturnValueConstraintLocation.java @@ -6,43 +6,45 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Executable; -import java.lang.reflect.Member; import java.lang.reflect.Type; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; -import org.hibernate.validator.internal.util.ReflectionHelper; /** * Executable return value constraint location. * * @author Hardy Ferentschik * @author Gunnar Morling + * @author Marko Bekhta + * @author Guillaume Smet */ class ReturnValueConstraintLocation implements ConstraintLocation { - private final Executable executable; - private final Type typeForValidatorResolution; + private final Callable callable; - ReturnValueConstraintLocation(Executable executable) { - this.executable = executable; - this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( executable ) ); + private final ConstraintLocationKind kind; + + ReturnValueConstraintLocation(Callable callable) { + this.callable = callable; + this.kind = ConstraintLocationKind.of( callable.getConstrainedElementKind() ); } @Override public Class getDeclaringClass() { - return executable.getDeclaringClass(); + return callable.getDeclaringClass(); } @Override - public Member getMember() { - return executable; + public Constrainable getConstrainable() { + return callable; } @Override public Type getTypeForValidatorResolution() { - return typeForValidatorResolution; + return callable.getTypeForValidatorResolution(); } @Override @@ -55,16 +57,21 @@ public Object getValue(Object parent) { return parent; } + @Override + public ConstraintLocationKind getKind() { + return kind; + } + @Override public String toString() { - return "ReturnValueConstraintLocation [executable=" + executable + "]"; + return "ReturnValueConstraintLocation [callable=" + callable + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ( ( executable == null ) ? 0 : executable.hashCode() ); + result = prime * result + callable.hashCode(); return result; } @@ -80,12 +87,7 @@ public boolean equals(Object obj) { return false; } ReturnValueConstraintLocation other = (ReturnValueConstraintLocation) obj; - if ( executable == null ) { - if ( other.executable != null ) { - return false; - } - } - else if ( !executable.equals( other.executable ) ) { + if ( !callable.equals( other.callable ) ) { return false; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/TypeArgumentConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/TypeArgumentConstraintLocation.java index 989d8a2c76..0f82da3644 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/TypeArgumentConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/TypeArgumentConstraintLocation.java @@ -6,11 +6,11 @@ */ package org.hibernate.validator.internal.metadata.location; -import java.lang.reflect.Member; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.StringHelper; @@ -52,8 +52,8 @@ public Class getDeclaringClass() { } @Override - public Member getMember() { - return delegate.getMember(); + public Constrainable getConstrainable() { + return delegate.getConstrainable(); } public TypeVariable getTypeParameter() { @@ -87,6 +87,11 @@ public ConstraintLocation getOuterDelegate() { return outerDelegate; } + @Override + public ConstraintLocationKind getKind() { + return ConstraintLocationKind.TYPE_USE; + } + @Override public String toString() { return "TypeArgumentValueConstraintLocation [typeForValidatorResolution=" + StringHelper.toShortString( typeForValidatorResolution ) 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 1b387b8e13..bb78e18691 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 @@ -12,20 +12,14 @@ import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES; import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; import java.lang.invoke.MethodHandles; -import java.lang.reflect.AccessibleObject; import java.lang.reflect.AnnotatedArrayType; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedParameterizedType; import java.lang.reflect.AnnotatedType; -import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; -import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; @@ -56,6 +50,7 @@ import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.raw.BeanConfiguration; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; @@ -63,8 +58,15 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; +import org.hibernate.validator.internal.properties.Property; +import org.hibernate.validator.internal.properties.javabean.JavaBeanAnnotatedConstrainable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanAnnotatedElement; +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.util.CollectionHelper; -import org.hibernate.validator.internal.util.ExecutableHelper; import org.hibernate.validator.internal.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; @@ -134,8 +136,6 @@ private BeanConfiguration retrieveBeanConfiguration(Class beanClass) { constrainedElements.addAll( getMethodMetaData( beanClass ) ); constrainedElements.addAll( getConstructorMetaData( beanClass ) ); - //TODO GM: currently class level constraints are represented by a PropertyMetaData. This - //works but seems somewhat unnatural Set> classLevelConstraints = getClassLevelConstraints( beanClass ); if ( !classLevelConstraints.isEmpty() ) { ConstrainedType classLevelMetaData = @@ -214,45 +214,46 @@ private Set getFieldMetaData(Class beanClass) { Set propertyMetaData = newHashSet(); for ( Field field : run( GetDeclaredFields.action( beanClass ) ) ) { + JavaBeanField javaBeanField = new JavaBeanField( field ); // HV-172 if ( Modifier.isStatic( field.getModifiers() ) || - annotationProcessingOptions.areMemberConstraintsIgnoredFor( field ) || + annotationProcessingOptions.areMemberConstraintsIgnoredFor( javaBeanField ) || field.isSynthetic() ) { continue; } - propertyMetaData.add( findPropertyMetaData( field ) ); + propertyMetaData.add( findPropertyMetaData( javaBeanField ) ); } return propertyMetaData; } - private ConstrainedField findPropertyMetaData(Field field) { + private ConstrainedField findPropertyMetaData(JavaBeanField javaBeanField) { Set> constraints = convertToMetaConstraints( - findConstraints( field, ElementType.FIELD ), - field + findConstraints( javaBeanField, ConstraintLocationKind.FIELD ), + javaBeanField ); - CascadingMetaDataBuilder cascadingMetaDataBuilder = findCascadingMetaData( field ); - Set> typeArgumentsConstraints = findTypeAnnotationConstraints( field ); + CascadingMetaDataBuilder cascadingMetaDataBuilder = findCascadingMetaData( javaBeanField ); + Set> typeArgumentsConstraints = findTypeAnnotationConstraints( javaBeanField ); return new ConstrainedField( ConfigurationSource.ANNOTATION, - field, + javaBeanField, constraints, typeArgumentsConstraints, cascadingMetaDataBuilder ); } - private Set> convertToMetaConstraints(List> constraintDescriptors, Field field) { + private Set> convertToMetaConstraints(List> constraintDescriptors, JavaBeanField javaBeanField) { if ( constraintDescriptors.isEmpty() ) { return Collections.emptySet(); } Set> constraints = newHashSet(); - ConstraintLocation location = ConstraintLocation.forField( field ); + ConstraintLocation location = ConstraintLocation.forField( javaBeanField ); for ( ConstraintDescriptorImpl constraintDescription : constraintDescriptors ) { constraints.add( MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescription, location ) ); @@ -297,20 +298,22 @@ private Set getMetaData(Executable[] executableElements) * given element. */ private ConstrainedExecutable findExecutableMetaData(Executable executable) { - List parameterConstraints = getParameterMetaData( executable ); + JavaBeanExecutable javaBeanExecutable = JavaBeanExecutable.of( executable ); + List parameterConstraints = getParameterMetaData( javaBeanExecutable ); - Map>> executableConstraints = findConstraints( executable, ExecutableHelper.getElementType( executable ) ) - .stream() - .collect( Collectors.groupingBy( ConstraintDescriptorImpl::getConstraintType ) ); + Map>> executableConstraints = findConstraints( + javaBeanExecutable, + ConstraintLocationKind.of( javaBeanExecutable.getConstrainedElementKind() ) + ).stream().collect( Collectors.groupingBy( ConstraintDescriptorImpl::getConstraintType ) ); Set> crossParameterConstraints; - if ( annotationProcessingOptions.areCrossParameterConstraintsIgnoredFor( executable ) ) { + if ( annotationProcessingOptions.areCrossParameterConstraintsIgnoredFor( javaBeanExecutable ) ) { crossParameterConstraints = Collections.emptySet(); } else { crossParameterConstraints = convertToMetaConstraints( executableConstraints.get( ConstraintType.CROSS_PARAMETER ), - executable + javaBeanExecutable ); } @@ -318,25 +321,23 @@ private ConstrainedExecutable findExecutableMetaData(Executable executable) { Set> typeArgumentsConstraints; CascadingMetaDataBuilder cascadingMetaDataBuilder; - if ( annotationProcessingOptions.areReturnValueConstraintsIgnoredFor( executable ) ) { + if ( annotationProcessingOptions.areReturnValueConstraintsIgnoredFor( javaBeanExecutable ) ) { returnValueConstraints = Collections.emptySet(); typeArgumentsConstraints = Collections.emptySet(); cascadingMetaDataBuilder = CascadingMetaDataBuilder.nonCascading(); } else { - AnnotatedType annotatedReturnType = executable.getAnnotatedReturnType(); - - typeArgumentsConstraints = findTypeAnnotationConstraints( executable, annotatedReturnType ); + typeArgumentsConstraints = findTypeAnnotationConstraints( javaBeanExecutable ); returnValueConstraints = convertToMetaConstraints( executableConstraints.get( ConstraintType.GENERIC ), - executable + javaBeanExecutable ); - cascadingMetaDataBuilder = findCascadingMetaData( executable, annotatedReturnType ); + cascadingMetaDataBuilder = findCascadingMetaData( javaBeanExecutable ); } return new ConstrainedExecutable( ConfigurationSource.ANNOTATION, - executable, + javaBeanExecutable, parameterConstraints, crossParameterConstraints, returnValueConstraints, @@ -345,15 +346,15 @@ private ConstrainedExecutable findExecutableMetaData(Executable executable) { ); } - private Set> convertToMetaConstraints(List> constraintsDescriptors, Executable executable) { + private Set> convertToMetaConstraints(List> constraintsDescriptors, Callable callable) { if ( constraintsDescriptors == null ) { return Collections.emptySet(); } Set> constraints = newHashSet(); - ConstraintLocation returnValueLocation = ConstraintLocation.forReturnValue( executable ); - ConstraintLocation crossParameterLocation = ConstraintLocation.forCrossParameter( executable ); + ConstraintLocation returnValueLocation = ConstraintLocation.forReturnValue( callable ); + ConstraintLocation crossParameterLocation = ConstraintLocation.forCrossParameter( callable ); for ( ConstraintDescriptorImpl constraintDescriptor : constraintsDescriptors ) { ConstraintLocation location = constraintDescriptor.getConstraintType() == ConstraintType.GENERIC ? returnValueLocation : crossParameterLocation; @@ -367,24 +368,24 @@ private Set> convertToMetaConstraints(List getParameterMetaData(Executable executable) { - if ( executable.getParameterCount() == 0 ) { + private List getParameterMetaData(JavaBeanExecutable javaBeanExecutable) { + if ( !javaBeanExecutable.hasParameters() ) { return Collections.emptyList(); } - Parameter[] parameters = executable.getParameters(); + List parameters = javaBeanExecutable.getParameters(); - List metaData = new ArrayList<>( parameters.length ); + List metaData = new ArrayList<>( parameters.size() ); int i = 0; - for ( Parameter parameter : parameters ) { + for ( JavaBeanParameter parameter : parameters ) { Annotation[] parameterAnnotations; try { - parameterAnnotations = parameter.getAnnotations(); + parameterAnnotations = parameter.getDeclaredAnnotations(); } catch (ArrayIndexOutOfBoundsException ex) { LOG.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex ); @@ -393,13 +394,12 @@ private List getParameterMetaData(Executable executable) { Set> parameterConstraints = newHashSet(); - if ( annotationProcessingOptions.areParameterConstraintsIgnoredFor( executable, i ) ) { - Type type = ReflectionHelper.typeOf( executable, i ); + if ( annotationProcessingOptions.areParameterConstraintsIgnoredFor( javaBeanExecutable, i ) ) { metaData.add( new ConstrainedParameter( ConfigurationSource.ANNOTATION, - executable, - type, + javaBeanExecutable, + parameter.getGenericType(), i, parameterConstraints, Collections.emptySet(), @@ -410,12 +410,12 @@ private List getParameterMetaData(Executable executable) { continue; } - ConstraintLocation location = ConstraintLocation.forParameter( executable, i ); + ConstraintLocation location = ConstraintLocation.forParameter( javaBeanExecutable, i ); for ( Annotation parameterAnnotation : parameterAnnotations ) { // collect constraints if this annotation is a constraint annotation List> constraints = findConstraintAnnotations( - executable, parameterAnnotation, ElementType.PARAMETER + javaBeanExecutable, parameterAnnotation, ConstraintLocationKind.PARAMETER ); for ( ConstraintDescriptorImpl constraintDescriptorImpl : constraints ) { parameterConstraints.add( @@ -424,16 +424,14 @@ private List getParameterMetaData(Executable executable) { } } - AnnotatedType parameterAnnotatedType = parameter.getAnnotatedType(); - - Set> typeArgumentsConstraints = findTypeAnnotationConstraintsForExecutableParameter( executable, i, parameterAnnotatedType ); - CascadingMetaDataBuilder cascadingMetaData = findCascadingMetaData( executable, parameters, i, parameterAnnotatedType ); + Set> typeArgumentsConstraints = findTypeAnnotationConstraintsForExecutableParameter( javaBeanExecutable, parameter ); + CascadingMetaDataBuilder cascadingMetaData = findCascadingMetaData( parameter ); metaData.add( new ConstrainedParameter( ConfigurationSource.ANNOTATION, - executable, - ReflectionHelper.typeOf( executable, i ), + javaBeanExecutable, + parameter.getGenericType(), i, parameterConstraints, typeArgumentsConstraints, @@ -450,15 +448,15 @@ private List getParameterMetaData(Executable executable) { * Finds all constraint annotations defined for the given member and returns them in a list of * constraint descriptors. * - * @param member The member to check for constraints annotations. + * @param constrainable The constrainable to check for constraint annotations. * @param type The element type the constraint/annotation is placed on. * * @return A list of constraint descriptors for all constraint specified for the given member. */ - private List> findConstraints(Member member, ElementType type) { + private List> findConstraints(JavaBeanAnnotatedConstrainable constrainable, ConstraintLocationKind type) { List> metaData = newArrayList(); - for ( Annotation annotation : ( (AccessibleObject) member ).getDeclaredAnnotations() ) { - metaData.addAll( findConstraintAnnotations( member, annotation, type ) ); + for ( Annotation annotation : constrainable.getDeclaredAnnotations() ) { + metaData.addAll( findConstraintAnnotations( constrainable, annotation, type ) ); } return metaData; @@ -475,7 +473,7 @@ private List> findConstraints(Member member, Element private List> findClassLevelConstraints(Class beanClass) { List> metaData = newArrayList(); for ( Annotation annotation : beanClass.getDeclaredAnnotations() ) { - metaData.addAll( findConstraintAnnotations( null, annotation, ElementType.TYPE ) ); + metaData.addAll( findConstraintAnnotations( null, annotation, ConstraintLocationKind.TYPE ) ); } return metaData; } @@ -483,7 +481,7 @@ private List> findClassLevelConstraints(Class bea /** * Examines the given annotation to see whether it is a single- or multi-valued constraint annotation. * - * @param member The member to check for constraints annotations + * @param constrainable The constrainable to check for constraints annotations * @param annotation The annotation to examine * @param type the element type on which the annotation/constraint is placed on * @param the annotation type @@ -491,9 +489,10 @@ private List> findClassLevelConstraints(Class bea * @return A list of constraint descriptors or the empty list in case {@code annotation} is neither a * single nor multi-valued annotation. */ - protected List> findConstraintAnnotations(Member member, + protected List> findConstraintAnnotations( + Constrainable constrainable, A annotation, - ElementType type) { + ConstraintLocationKind type) { // HV-1049 and HV-1311 - Ignore annotations from the JDK (jdk.internal.* and java.*); They cannot be constraint // annotations so skip them right here, as for the proper check we'd need package access permission for @@ -512,14 +511,14 @@ else if ( constraintHelper.isMultiValueConstraint( annotationType ) ) { } return constraints.stream() - .map( c -> buildConstraintDescriptor( member, c, type ) ) + .map( c -> buildConstraintDescriptor( constrainable, c, type ) ) .collect( Collectors.toList() ); } - private Map, Class> getGroupConversions(AnnotatedElement annotatedElement) { + private Map, Class> getGroupConversions(AnnotatedType annotatedType) { return getGroupConversions( - annotatedElement.getAnnotation( ConvertGroup.class ), - annotatedElement.getAnnotation( ConvertGroup.List.class ) + annotatedType.getAnnotation( ConvertGroup.class ), + annotatedType.getAnnotation( ConvertGroup.List.class ) ); } @@ -549,12 +548,12 @@ private Map, Class> getGroupConversions(ConvertGroup groupConversion return groupConversions; } - private ConstraintDescriptorImpl buildConstraintDescriptor(Member member, + private ConstraintDescriptorImpl buildConstraintDescriptor(Constrainable constrainable, A annotation, - ElementType type) { + ConstraintLocationKind type) { return new ConstraintDescriptorImpl<>( constraintHelper, - member, + constrainable, new ConstraintAnnotationDescriptor<>( annotation ), type ); @@ -573,35 +572,31 @@ private T run(PrivilegedAction action) { /** * Finds type arguments constraints for fields. */ - protected Set> findTypeAnnotationConstraints(Field field) { + protected Set> findTypeAnnotationConstraints(JavaBeanField javaBeanField) { return findTypeArgumentsConstraints( - field, - new TypeArgumentFieldLocation( field ), - field.getAnnotatedType() + javaBeanField, + new TypeArgumentFieldLocation( javaBeanField ), + javaBeanField.getAnnotatedType() ); } /** * Finds type arguments constraints for method return values. */ - protected Set> findTypeAnnotationConstraints(Executable executable, AnnotatedType annotatedReturnType) { + protected Set> findTypeAnnotationConstraints(JavaBeanExecutable javaBeanExecutable) { return findTypeArgumentsConstraints( - executable, - new TypeArgumentReturnValueLocation( executable ), - annotatedReturnType + javaBeanExecutable, + new TypeArgumentReturnValueLocation( javaBeanExecutable ), + javaBeanExecutable.getAnnotatedType() ); } - private CascadingMetaDataBuilder findCascadingMetaData(Executable executable, Parameter[] parameters, int i, AnnotatedType parameterAnnotatedType) { - Parameter parameter = parameters[i]; - TypeVariable[] typeParameters = parameter.getType().getTypeParameters(); - - Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( parameterAnnotatedType, - typeParameters ); + private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanParameter javaBeanParameter) { + Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( javaBeanParameter.getAnnotatedType(), + javaBeanParameter.getTypeParameters() ); try { - return getCascadingMetaData( ReflectionHelper.typeOf( parameter.getDeclaringExecutable(), i ), - parameter, containerElementTypesCascadingMetaData ); + return getCascadingMetaData( javaBeanParameter, containerElementTypesCascadingMetaData ); } catch (ArrayIndexOutOfBoundsException ex) { LOG.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex ); @@ -609,29 +604,19 @@ private CascadingMetaDataBuilder findCascadingMetaData(Executable executable, Pa } } - private CascadingMetaDataBuilder findCascadingMetaData(Field field) { - TypeVariable[] typeParameters = field.getType().getTypeParameters(); - AnnotatedType annotatedType = field.getAnnotatedType(); + private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanField javaBeanField) { + Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( + javaBeanField.getAnnotatedType(), + javaBeanField.getTypeParameters() ); - Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( annotatedType, typeParameters ); - - return getCascadingMetaData( ReflectionHelper.typeOf( field ), field, containerElementTypesCascadingMetaData ); + return getCascadingMetaData( javaBeanField, containerElementTypesCascadingMetaData ); } - private CascadingMetaDataBuilder findCascadingMetaData(Executable executable, AnnotatedType annotatedReturnType) { - TypeVariable[] typeParameters; - - if ( executable instanceof Method ) { - typeParameters = ( (Method) executable ).getReturnType().getTypeParameters(); - } - else { - typeParameters = ( (Constructor) executable ).getDeclaringClass().getTypeParameters(); - } - - Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( annotatedReturnType, - typeParameters ); + private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanExecutable javaBeanExecutable) { + Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( javaBeanExecutable.getAnnotatedType(), + javaBeanExecutable.getTypeParameters() ); - return getCascadingMetaData( ReflectionHelper.typeOf( executable ), executable, containerElementTypesCascadingMetaData ); + return getCascadingMetaData( javaBeanExecutable, containerElementTypesCascadingMetaData ); } private Map, CascadingMetaDataBuilder> getTypeParametersCascadingMetadata(AnnotatedType annotatedType, @@ -702,17 +687,17 @@ else if ( annotatedType instanceof AnnotatedParameterizedType ) { /** * Finds type arguments constraints for parameters. * - * @param executable the executable - * @param i the parameter index + * @param javaBeanParameter the parameter * * @return a set of type arguments constraints, or an empty set if no constrained type arguments are found */ - protected Set> findTypeAnnotationConstraintsForExecutableParameter(Executable executable, int i, AnnotatedType parameterAnnotatedType) { + protected Set> findTypeAnnotationConstraintsForExecutableParameter(JavaBeanExecutable javaBeanExecutable, + JavaBeanParameter javaBeanParameter) { try { return findTypeArgumentsConstraints( - executable, - new TypeArgumentExecutableParameterLocation( executable, i ), - parameterAnnotatedType + javaBeanExecutable, + new TypeArgumentExecutableParameterLocation( javaBeanExecutable, javaBeanParameter.getIndex() ), + javaBeanParameter.getAnnotatedType() ); } catch (ArrayIndexOutOfBoundsException ex) { @@ -721,7 +706,7 @@ protected Set> findTypeAnnotationConstraintsForExecutableParam } } - private Set> findTypeArgumentsConstraints(Member member, TypeArgumentLocation location, AnnotatedType annotatedType) { + private Set> findTypeArgumentsConstraints(Constrainable constrainable, TypeArgumentLocation location, AnnotatedType annotatedType) { // HV-1428 Container element support is disabled for arrays if ( !(annotatedType instanceof AnnotatedParameterizedType) ) { return Collections.emptySet(); @@ -735,9 +720,9 @@ private Set> findTypeArgumentsConstraints(Member member, TypeA Type validatedType = annotatedArrayType.getAnnotatedGenericComponentType().getType(); TypeVariable arrayElementTypeArgument = new ArrayElement( annotatedArrayType ); - typeArgumentConstraints.addAll( findTypeUseConstraints( member, annotatedArrayType, arrayElementTypeArgument, location, validatedType ) ); + typeArgumentConstraints.addAll( findTypeUseConstraints( constrainable, annotatedArrayType, arrayElementTypeArgument, location, validatedType ) ); - typeArgumentConstraints.addAll( findTypeArgumentsConstraints( member, + typeArgumentConstraints.addAll( findTypeArgumentsConstraints( constrainable, new NestedTypeArgumentLocation( location, arrayElementTypeArgument, validatedType ), annotatedArrayType.getAnnotatedGenericComponentType() ) ); } @@ -755,10 +740,10 @@ else if ( annotatedType instanceof AnnotatedParameterizedType ) { // In the latter case a value unwrapping has to occur Type validatedType = annotatedTypeParameter.getType(); - typeArgumentConstraints.addAll( findTypeUseConstraints( member, annotatedTypeParameter, typeVariable, location, validatedType ) ); + typeArgumentConstraints.addAll( findTypeUseConstraints( constrainable, annotatedTypeParameter, typeVariable, location, validatedType ) ); if ( validatedType instanceof ParameterizedType ) { - typeArgumentConstraints.addAll( findTypeArgumentsConstraints( member, + typeArgumentConstraints.addAll( findTypeArgumentsConstraints( constrainable, new NestedTypeArgumentLocation( location, typeVariable, validatedType ), annotatedTypeParameter ) ); } @@ -773,9 +758,9 @@ else if ( annotatedType instanceof AnnotatedParameterizedType ) { /** * Finds type use annotation constraints defined on the type argument. */ - private Set> findTypeUseConstraints(Member member, AnnotatedType typeArgument, TypeVariable typeVariable, TypeArgumentLocation location, Type type) { + private Set> findTypeUseConstraints(Constrainable constrainable, AnnotatedType typeArgument, TypeVariable typeVariable, TypeArgumentLocation location, Type type) { Set> constraints = Arrays.stream( typeArgument.getAnnotations() ) - .flatMap( a -> findConstraintAnnotations( member, a, ElementType.TYPE_USE ).stream() ) + .flatMap( a -> findConstraintAnnotations( constrainable, a, ConstraintLocationKind.TYPE_USE ).stream() ) .map( d -> createTypeArgumentMetaConstraint( d, location, typeVariable, type ) ) .collect( Collectors.toSet() ); @@ -791,17 +776,17 @@ private MetaConstraint createTypeArgumentMetaConstrain return MetaConstraints.create( typeResolutionHelper, valueExtractorManager, descriptor, constraintLocation ); } - private CascadingMetaDataBuilder getCascadingMetaData(Type type, AnnotatedElement annotatedElement, + private CascadingMetaDataBuilder getCascadingMetaData(JavaBeanAnnotatedElement annotatedElement, Map, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData) { - return CascadingMetaDataBuilder.annotatedObject( type, annotatedElement.isAnnotationPresent( Valid.class ), containerElementTypesCascadingMetaData, - getGroupConversions( annotatedElement ) ); + return CascadingMetaDataBuilder.annotatedObject( annotatedElement.getType(), annotatedElement.isAnnotationPresent( Valid.class ), + containerElementTypesCascadingMetaData, getGroupConversions( annotatedElement.getAnnotatedType() ) ); } /** * The location of a type argument before it is really considered a constraint location. *

* It avoids initializing a constraint location if we did not find any constraints. This is especially useful in - * a Java 9 environment as {@link ConstraintLocation#forProperty(Member) tries to make the {@code Member} accessible + * a Java 9 environment as {@link ConstraintLocation#forProperty(Property)} tries to make the {@code Member} accessible * which might not be possible (for instance for {@code java.util} classes). */ private interface TypeArgumentLocation { @@ -809,44 +794,44 @@ private interface TypeArgumentLocation { } private static class TypeArgumentExecutableParameterLocation implements TypeArgumentLocation { - private final Executable executable; + private final JavaBeanExecutable javaBeanExecutable; private final int index; - private TypeArgumentExecutableParameterLocation(Executable executable, int index) { - this.executable = executable; + private TypeArgumentExecutableParameterLocation(JavaBeanExecutable javaBeanExecutable, int index) { + this.javaBeanExecutable = javaBeanExecutable; this.index = index; } @Override public ConstraintLocation toConstraintLocation() { - return ConstraintLocation.forParameter( executable, index ); + return ConstraintLocation.forParameter( javaBeanExecutable, index ); } } private static class TypeArgumentFieldLocation implements TypeArgumentLocation { - private final Field field; + private final JavaBeanField javaBeanField; - private TypeArgumentFieldLocation(Field field) { - this.field = field; + private TypeArgumentFieldLocation(JavaBeanField javaBeanField) { + this.javaBeanField = javaBeanField; } @Override public ConstraintLocation toConstraintLocation() { - return ConstraintLocation.forField( field ); + return ConstraintLocation.forField( javaBeanField ); } } private static class TypeArgumentReturnValueLocation implements TypeArgumentLocation { - private final Executable executable; + private final JavaBeanExecutable javaBeanExecutable; - private TypeArgumentReturnValueLocation(Executable executable) { - this.executable = executable; + private TypeArgumentReturnValueLocation(JavaBeanExecutable javaBeanExecutable) { + this.javaBeanExecutable = javaBeanExecutable; } @Override public ConstraintLocation toConstraintLocation() { - return ConstraintLocation.forReturnValue( executable ); + return ConstraintLocation.forReturnValue( javaBeanExecutable ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedElement.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedElement.java index fc7114ab4e..a1b1c456fd 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedElement.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedElement.java @@ -40,16 +40,6 @@ */ public interface ConstrainedElement extends Iterable> { - /** - * The kind of a {@link ConstrainedElement}. Can be used to determine an - * element's type when traversing over a collection of constrained elements. - * - * @author Gunnar Morling - */ - enum ConstrainedElementKind { - TYPE, FIELD, CONSTRUCTOR, METHOD, PARAMETER - } - /** * Returns the kind of this constrained element. * @@ -91,4 +81,28 @@ enum ConstrainedElementKind { * Returns the configuration source contributing this constrained element. */ ConfigurationSource getSource(); + + /** + * The kind of a {@link ConstrainedElement}. Can be used to determine an + * element's type when traversing over a collection of constrained elements. + * + * @author Gunnar Morling + */ + enum ConstrainedElementKind { + + TYPE, + FIELD, + CONSTRUCTOR, + METHOD, + PARAMETER, + GETTER; + + public boolean isExecutable() { + return this == CONSTRUCTOR || isMethod(); + } + + public boolean isMethod() { + return this == METHOD || this == GETTER; + } + } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedExecutable.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedExecutable.java index 8069e49cd3..2d9a612929 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedExecutable.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedExecutable.java @@ -10,8 +10,6 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -21,9 +19,8 @@ import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder; import org.hibernate.validator.internal.metadata.core.MetaConstraint; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.CollectionHelper; -import org.hibernate.validator.internal.util.ReflectionHelper; -import org.hibernate.validator.internal.util.StringHelper; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; import org.hibernate.validator.internal.util.stereotypes.Immutable; @@ -40,7 +37,7 @@ public class ConstrainedExecutable extends AbstractConstrainedElement { private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); - private final Executable executable; + private final Callable callable; /** * Constrained-related meta data for this executable's parameters. @@ -53,13 +50,11 @@ public class ConstrainedExecutable extends AbstractConstrainedElement { @Immutable private final Set> crossParameterConstraints; - private final boolean isGetterMethod; - /** * Creates a new executable meta data object for a parameter-less executable. * * @param source The source of meta data. - * @param executable The represented executable. + * @param callable The represented executable. * @param returnValueConstraints Type arguments constraints, if any. * @param typeArgumentConstraints The type argument constraints on the return value of the represented executable, * if any. @@ -67,13 +62,13 @@ public class ConstrainedExecutable extends AbstractConstrainedElement { */ public ConstrainedExecutable( ConfigurationSource source, - Executable executable, + Callable callable, Set> returnValueConstraints, Set> typeArgumentConstraints, CascadingMetaDataBuilder cascadingMetaDataBuilder) { this( source, - executable, + callable, Collections.emptyList(), Collections.>emptySet(), returnValueConstraints, @@ -86,7 +81,7 @@ public ConstrainedExecutable( * Creates a new executable meta data object. * * @param source The source of meta data. - * @param executable The represented executable. + * @param callable The represented executable. * @param parameterMetaData A list with parameter meta data. The length must correspond with the number of * parameters of the represented executable. So this list may be empty (in case of a parameterless executable), but * never {@code null}. @@ -98,7 +93,7 @@ public ConstrainedExecutable( */ public ConstrainedExecutable( ConfigurationSource source, - Executable executable, + Callable callable, List parameterMetaData, Set> crossParameterConstraints, Set> returnValueConstraints, @@ -106,18 +101,18 @@ public ConstrainedExecutable( CascadingMetaDataBuilder cascadingMetaDataBuilder) { super( source, - ( executable instanceof Constructor ) ? ConstrainedElementKind.CONSTRUCTOR : ConstrainedElementKind.METHOD, + callable.getConstrainedElementKind(), returnValueConstraints, typeArgumentConstraints, cascadingMetaDataBuilder ); - this.executable = executable; + this.callable = callable; - if ( parameterMetaData.size() != executable.getParameterTypes().length ) { + if ( parameterMetaData.size() != callable.getParameterCount() ) { throw LOG.getInvalidLengthOfParameterMetaDataListException( - executable, - executable.getParameterTypes().length, + callable, + callable.getParameterCount(), parameterMetaData.size() ); } @@ -125,7 +120,6 @@ public ConstrainedExecutable( this.crossParameterConstraints = CollectionHelper.toImmutableSet( crossParameterConstraints ); this.parameterMetaData = CollectionHelper.toImmutableList( parameterMetaData ); this.hasParameterConstraints = hasParameterConstraints( parameterMetaData ) || !crossParameterConstraints.isEmpty(); - this.isGetterMethod = ReflectionHelper.isGetterMethod( executable ); } /** @@ -142,7 +136,7 @@ public ConstrainedExecutable( public ConstrainedParameter getParameterMetaData(int parameterIndex) { if ( parameterIndex < 0 || parameterIndex > parameterMetaData.size() - 1 ) { throw LOG.getInvalidExecutableParameterIndexException( - executable, + callable, parameterIndex ); } @@ -192,23 +186,13 @@ public boolean hasParameterConstraints() { return hasParameterConstraints; } - /** - * Whether the represented executable is a JavaBeans getter executable or not. - * - * @return {@code True}, if this executable is a getter method, {@code false} - * otherwise. - */ - public boolean isGetterMethod() { - return isGetterMethod; - } - - public Executable getExecutable() { - return executable; + public Callable getCallable() { + return callable; } @Override public String toString() { - return "ConstrainedExecutable [executable=" + StringHelper.toShortString( executable ) + return "ConstrainedExecutable [executable=" + callable + ", parameterMetaData=" + parameterMetaData + ", hasParameterConstraints=" + hasParameterConstraints + "]"; } @@ -284,7 +268,7 @@ public ConstrainedExecutable merge(ConstrainedExecutable other) { return new ConstrainedExecutable( mergedSource, - executable, + callable, mergedParameterMetaData, mergedCrossParameterConstraints, mergedReturnValueConstraints, @@ -307,8 +291,7 @@ private Set> getDescriptors(Iterable> public int hashCode() { final int prime = 31; int result = super.hashCode(); - result = prime * result - + ( ( executable == null ) ? 0 : executable.hashCode() ); + result = prime * result + callable.hashCode(); return result; } @@ -324,12 +307,7 @@ public boolean equals(Object obj) { return false; } ConstrainedExecutable other = (ConstrainedExecutable) obj; - if ( executable == null ) { - if ( other.executable != null ) { - return false; - } - } - else if ( !executable.equals( other.executable ) ) { + if ( !callable.equals( other.callable ) ) { return false; } return true; diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedField.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedField.java index cc889ae089..143ad0fcc0 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedField.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedField.java @@ -6,12 +6,11 @@ */ package org.hibernate.validator.internal.metadata.raw; -import java.lang.reflect.Field; import java.util.Set; import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder; import org.hibernate.validator.internal.metadata.core.MetaConstraint; -import org.hibernate.validator.internal.util.StringHelper; +import org.hibernate.validator.internal.properties.Field; /** * Represents a field of a Java type and all its associated meta-data relevant @@ -19,6 +18,7 @@ * * @author Gunnar Morling * @author Guillaume Smet + * @author Marko Bekhta */ public class ConstrainedField extends AbstractConstrainedElement { @@ -34,30 +34,29 @@ public class ConstrainedField extends AbstractConstrainedElement { * @param cascadingMetaDataBuilder The cascaded validation metadata for this element and its container elements. */ public ConstrainedField(ConfigurationSource source, - Field field, - Set> constraints, - Set> typeArgumentConstraints, - CascadingMetaDataBuilder cascadingMetaDataBuilder) { + Field field, + Set> constraints, + Set> typeArgumentConstraints, + CascadingMetaDataBuilder cascadingMetaDataBuilder) { super( source, ConstrainedElementKind.FIELD, constraints, typeArgumentConstraints, cascadingMetaDataBuilder ); this.field = field; + } public Field getField() { return field; } - @Override public String toString() { - return "ConstrainedField [field=" + StringHelper.toShortString( field ) + "]"; + return "ConstrainedField [field=" + field.getName() + "]"; } @Override public int hashCode() { - final int prime = 31; int result = super.hashCode(); - result = prime * result + ( ( field == null ) ? 0 : field.hashCode() ); + result = 31 * result + this.field.hashCode(); return result; } @@ -73,14 +72,6 @@ public boolean equals(Object obj) { return false; } ConstrainedField other = (ConstrainedField) obj; - if ( field == null ) { - if ( other.field != null ) { - return false; - } - } - else if ( !field.equals( other.field ) ) { - return false; - } - return true; + return this.field.equals( other.field ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedParameter.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedParameter.java index d8d161d764..dab9ac417c 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedParameter.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/raw/ConstrainedParameter.java @@ -8,7 +8,6 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; -import java.lang.reflect.Executable; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; @@ -16,6 +15,7 @@ import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder; import org.hibernate.validator.internal.metadata.core.MetaConstraint; +import org.hibernate.validator.internal.properties.Callable; /** * Contains constraint-related meta-data for one method parameter. @@ -25,17 +25,17 @@ */ public class ConstrainedParameter extends AbstractConstrainedElement { - private final Executable executable; + private final Callable callable; private final Type type; private final int index; public ConstrainedParameter(ConfigurationSource source, - Executable executable, + Callable callable, Type type, int index) { this( source, - executable, + callable, type, index, Collections.>emptySet(), @@ -48,7 +48,7 @@ public ConstrainedParameter(ConfigurationSource source, * Creates a new parameter meta data object. * * @param source The source of meta data. - * @param executable The executable of the represented method parameter. + * @param callable The executable of the represented method parameter. * @param type the parameter type * @param index the index of the parameter * @param constraints The constraints of the represented method parameter, if @@ -57,7 +57,7 @@ public ConstrainedParameter(ConfigurationSource source, * @param cascadingMetaDataBuilder The cascaded validation metadata for this element and its container elements. */ public ConstrainedParameter(ConfigurationSource source, - Executable executable, + Callable callable, Type type, int index, Set> constraints, @@ -71,7 +71,7 @@ public ConstrainedParameter(ConfigurationSource source, cascadingMetaDataBuilder ); - this.executable = executable; + this.callable = callable; this.type = type; this.index = index; } @@ -80,8 +80,8 @@ public Type getType() { return type; } - public Executable getExecutable() { - return executable; + public Callable getCallable() { + return callable; } public int getIndex() { @@ -109,7 +109,7 @@ public ConstrainedParameter merge(ConstrainedParameter other) { return new ConstrainedParameter( mergedSource, - executable, + callable, type, index, mergedConstraints, @@ -130,7 +130,7 @@ public String toString() { String constraintsAsString = sb.length() > 0 ? sb.substring( 0, sb.length() - 2 ) : sb.toString(); - return "ParameterMetaData [executable=" + executable + ", index=" + index + "], constraints=[" + return "ParameterMetaData [callable=" + callable + ", index=" + index + "], constraints=[" + constraintsAsString + "]"; } @@ -139,7 +139,7 @@ public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + index; - result = prime * result + ( ( executable == null ) ? 0 : executable.hashCode() ); + result = prime * result + callable.hashCode(); return result; } @@ -158,12 +158,7 @@ public boolean equals(Object obj) { if ( index != other.index ) { return false; } - if ( executable == null ) { - if ( other.executable != null ) { - return false; - } - } - else if ( !executable.equals( other.executable ) ) { + else if ( !callable.equals( other.callable ) ) { return false; } return true; diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/Callable.java b/engine/src/main/java/org/hibernate/validator/internal/properties/Callable.java new file mode 100644 index 0000000000..9ef259f46d --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/Callable.java @@ -0,0 +1,40 @@ +/* + * 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; + +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.util.ExecutableHelper; +import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; + +/** + * @author Marko Bekhta + * @author Guillaume Smet + */ +public interface Callable extends Constrainable { + + boolean hasReturnValue(); + + boolean hasParameters(); + + int getParameterCount(); + + Type getParameterGenericType(int index); + + Class[] getParameterTypes(); + + String getParameterName(ExecutableParameterNameProvider parameterNameProvider, int parameterIndex); + + boolean isPrivate(); + + String getSignature(); + + boolean overrides(ExecutableHelper executableHelper, Callable superTypeMethod); + + boolean isResolvedToSameMethodInHierarchy(ExecutableHelper executableHelper, Class mainSubType, Callable superTypeMethod); + +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/Constrainable.java b/engine/src/main/java/org/hibernate/validator/internal/properties/Constrainable.java new file mode 100644 index 0000000000..0accde036d --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/Constrainable.java @@ -0,0 +1,32 @@ +/* + * 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; + +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; + +/** + * @author Marko Bekhta + */ +public interface Constrainable { + + String getName(); + + Class getDeclaringClass(); + + Type getTypeForValidatorResolution(); + + Type getType(); + + ConstrainedElementKind getConstrainedElementKind(); + + @SuppressWarnings("unchecked") + default T as(Class clazz) { + return ( (T) this ); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/ConstrainableType.java b/engine/src/main/java/org/hibernate/validator/internal/properties/ConstrainableType.java new file mode 100644 index 0000000000..01356e09de --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/ConstrainableType.java @@ -0,0 +1,14 @@ +/* + * 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; + +/** + * @author Marko Bekhta + */ +public interface ConstrainableType { + +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/Field.java b/engine/src/main/java/org/hibernate/validator/internal/properties/Field.java new file mode 100644 index 0000000000..65d72330da --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/Field.java @@ -0,0 +1,20 @@ +/* + * 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; + +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; + +/** + * @author Guillaume Smet + */ +public interface Field extends Property { + + @Override + default ConstrainedElementKind getConstrainedElementKind() { + return ConstrainedElementKind.FIELD; + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/Getter.java b/engine/src/main/java/org/hibernate/validator/internal/properties/Getter.java new file mode 100644 index 0000000000..fede3102bd --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/Getter.java @@ -0,0 +1,20 @@ +/* + * 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; + +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; + +/** + * @author Guillaume Smet + */ +public interface Getter extends Property { + + @Override + default ConstrainedElementKind getConstrainedElementKind() { + return ConstrainedElementKind.GETTER; + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/Property.java b/engine/src/main/java/org/hibernate/validator/internal/properties/Property.java new file mode 100644 index 0000000000..12018421e0 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/Property.java @@ -0,0 +1,17 @@ +/* + * 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; + +/** + * @author Marko Bekhta + */ +public interface Property extends Constrainable { + + String getPropertyName(); + + PropertyAccessor createAccessor(); +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/PropertyAccessor.java b/engine/src/main/java/org/hibernate/validator/internal/properties/PropertyAccessor.java new file mode 100644 index 0000000000..b269dbb778 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/PropertyAccessor.java @@ -0,0 +1,15 @@ +/* + * 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; + +/** + * @author Guillaume Smet + */ +public interface PropertyAccessor { + + Object getValueFrom(Object bean); +} 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 new file mode 100644 index 0000000000..ff9dd436dc --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBean.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; + +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/JavaBeanAnnotatedConstrainable.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanAnnotatedConstrainable.java new file mode 100644 index 0000000000..55589a6c4a --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanAnnotatedConstrainable.java @@ -0,0 +1,16 @@ +/* + * 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 org.hibernate.validator.internal.properties.Constrainable; + +/** + * @author Guillaume Smet + */ +public interface JavaBeanAnnotatedConstrainable extends Constrainable, JavaBeanAnnotatedElement { + +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanAnnotatedElement.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanAnnotatedElement.java new file mode 100644 index 0000000000..11a99d3eab --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanAnnotatedElement.java @@ -0,0 +1,34 @@ +/* + * 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.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; + +/** + * @author Guillaume Smet + */ +public interface JavaBeanAnnotatedElement { + + Type getType(); + + AnnotatedType getAnnotatedType(); + + Annotation[] getDeclaredAnnotations(); + + Type getGenericType(); + + TypeVariable[] getTypeParameters(); + + A getAnnotation(Class annotationClass); + + default boolean isAnnotationPresent(Class annotationClass) { + return getAnnotation( annotationClass ) != null; + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanConstructor.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanConstructor.java new file mode 100644 index 0000000000..2ffbce8677 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanConstructor.java @@ -0,0 +1,32 @@ +/* + * 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.lang.reflect.Constructor; +import java.lang.reflect.TypeVariable; + +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; + +/** + * @author Guillaume Smet + */ +public class JavaBeanConstructor extends JavaBeanExecutable> { + + public JavaBeanConstructor(Constructor executable) { + super( executable, true ); + } + + @Override + public ConstrainedElementKind getConstrainedElementKind() { + return ConstrainedElementKind.CONSTRUCTOR; + } + + @Override + public TypeVariable[] getTypeParameters() { + return executable.getDeclaringClass().getTypeParameters(); + } +} 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 new file mode 100644 index 0000000000..baec5ef197 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanExecutable.java @@ -0,0 +1,232 @@ +/* + * 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.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.util.CollectionHelper; +import org.hibernate.validator.internal.util.ExecutableHelper; +import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; +import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.util.TypeHelper; + +/** + * @author Marko Bekhta + * @author Guillaume Smet + */ +public abstract class JavaBeanExecutable implements Callable, JavaBeanAnnotatedConstrainable { + + protected final T executable; + private final Type typeForValidatorResolution; + private final boolean hasReturnValue; + private final Type type; + private final List parameters; + + JavaBeanExecutable(T executable, boolean hasReturnValue) { + this.executable = executable; + this.type = ReflectionHelper.typeOf( executable ); + this.typeForValidatorResolution = ReflectionHelper.boxedType( type ); + this.hasReturnValue = hasReturnValue; + + if ( executable.getParameterCount() > 0 ) { + List parameters = new ArrayList<>( executable.getParameterCount() ); + + Parameter[] parameterArray = executable.getParameters(); + Class[] parameterTypes = executable.getParameterTypes(); + Type[] genericParameterTypes = executable.getGenericParameterTypes(); + + for ( int i = 0; i < parameterArray.length; i++ ) { + parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], + getParameterGenericType( parameterTypes, genericParameterTypes, i ) ) ); + } + this.parameters = CollectionHelper.toImmutableList( parameters ); + } + else { + this.parameters = Collections.emptyList(); + } + } + + public static JavaBeanExecutable of(Executable executable) { + if ( executable instanceof Constructor ) { + return new JavaBeanConstructor( (Constructor) executable ); + } + + return of( ( (Method) executable ) ); + } + + public static JavaBeanMethod of(Method method) { + if ( ReflectionHelper.isGetterMethod( method ) ) { + return new JavaBeanGetter( method ); + } + + return new JavaBeanMethod( method ); + } + + @Override + public boolean hasReturnValue() { + return hasReturnValue; + } + + @Override + public boolean hasParameters() { + return !parameters.isEmpty(); + } + + @Override + public String getName() { + return executable.getName(); + } + + @Override + public Class getDeclaringClass() { + return executable.getDeclaringClass(); + } + + @Override + public Type getTypeForValidatorResolution() { + return typeForValidatorResolution; + } + + @Override + public Type getType() { + return type; + } + + @Override + public String getParameterName(ExecutableParameterNameProvider parameterNameProvider, int parameterIndex) { + return parameterNameProvider.getParameterNames( executable ).get( parameterIndex ); + } + + @Override + public boolean isPrivate() { + return Modifier.isPrivate( executable.getModifiers() ); + } + + @Override + public String getSignature() { + return ExecutableHelper.getSignature( executable ); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return executable.getDeclaredAnnotations(); + } + + @Override + public boolean overrides(ExecutableHelper executableHelper, Callable superTypeMethod) { + return executableHelper.overrides( ( (Method) this.executable ), ( (Method) ( (JavaBeanExecutable) superTypeMethod ).executable ) ); + } + + @Override + public boolean isResolvedToSameMethodInHierarchy(ExecutableHelper executableHelper, Class mainSubType, Callable superTypeMethod) { + return executableHelper.isResolvedToSameMethodInHierarchy( mainSubType, ( (Method) this.executable ), ( (Method) ( (JavaBeanExecutable) superTypeMethod ).executable ) ); + } + + @Override + public Type getGenericType() { + return ReflectionHelper.typeOf( executable ); + } + + @Override + public AnnotatedType getAnnotatedType() { + return executable.getAnnotatedReturnType(); + } + + @Override + public A getAnnotation(Class annotationClass) { + return executable.getAnnotation( annotationClass ); + } + + public List getParameters() { + return parameters; + } + + @Override + public Type getParameterGenericType(int index) { + return parameters.get( index ).getGenericType(); + } + + @Override + public int getParameterCount() { + return parameters.size(); + } + + @Override + public Class[] getParameterTypes() { + return executable.getParameterTypes(); + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || this.getClass() != o.getClass() ) { + return false; + } + + JavaBeanExecutable that = (JavaBeanExecutable) o; + + if ( this.hasReturnValue != that.hasReturnValue ) { + return false; + } + if ( !this.executable.equals( that.executable ) ) { + return false; + } + if ( !this.typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { + return false; + } + return this.type.equals( that.type ); + } + + @Override + public int hashCode() { + int result = this.executable.hashCode(); + result = 31 * result + this.typeForValidatorResolution.hashCode(); + result = 31 * result + ( this.hasReturnValue ? 1 : 0 ); + result = 31 * result + this.type.hashCode(); + return result; + } + + @Override + public String toString() { + return ExecutableHelper.getExecutableAsString( + getDeclaringClass().getSimpleName() + "#" + executable.getName(), + executable.getParameterTypes() + ); + } + + private static Type getParameterGenericType(Type[] parameterTypes, Type[] genericParameterTypes, int parameterIndex) { + // getGenericParameterTypes() doesn't return synthetic parameters; in this case fall back to getParameterTypes() + Type[] typesToConsider; + if ( parameterIndex >= genericParameterTypes.length ) { + typesToConsider = parameterTypes; + } + else { + typesToConsider = genericParameterTypes; + } + + Type type = typesToConsider[parameterIndex]; + + if ( type instanceof TypeVariable ) { + type = TypeHelper.getErasedType( type ); + } + return type; + } +} 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 new file mode 100644 index 0000000000..647a33a3de --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanField.java @@ -0,0 +1,162 @@ +/* + * 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.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +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.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 Field field; + private final Type typeForValidatorResolution; + private final Type type; + + public JavaBeanField(Field field) { + this.field = field; + this.type = ReflectionHelper.typeOf( field ); + this.typeForValidatorResolution = ReflectionHelper.boxedType( this.type ); + } + + @Override + public String getName() { + return field.getName(); + } + + @Override + public Class getDeclaringClass() { + return field.getDeclaringClass(); + } + + @Override + public Type getType() { + return type; + } + + @Override + public Type getTypeForValidatorResolution() { + return typeForValidatorResolution; + } + + @Override + public String getPropertyName() { + return getName(); + } + + @Override + public AnnotatedType getAnnotatedType() { + return field.getAnnotatedType(); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return field.getDeclaredAnnotations(); + } + + @Override + public A getAnnotation(Class annotationClass) { + return field.getAnnotation( annotationClass ); + } + + @Override + public Type getGenericType() { + return ReflectionHelper.typeOf( field ); + } + + @Override + public TypeVariable[] getTypeParameters() { + return field.getType().getTypeParameters(); + } + + @Override + public PropertyAccessor createAccessor() { + return new FieldAccessor( field ); + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || this.getClass() != o.getClass() ) { + return false; + } + + JavaBeanField that = (JavaBeanField) o; + + if ( !this.field.equals( that.field ) ) { + return false; + } + if ( !this.typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { + return false; + } + return this.type.equals( that.type ); + } + + @Override + public int hashCode() { + int result = this.field.hashCode(); + result = 31 * result + this.typeForValidatorResolution.hashCode(); + result = 31 * result + this.type.hashCode(); + return result; + } + + @Override + 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 new file mode 100644 index 0000000000..a7084b1f9e --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanGetter.java @@ -0,0 +1,147 @@ +/* + * 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.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.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 String name; + + /** + * The class of the method for which the constraint was defined. + *

+ * It is usually the same as the declaring class of the method itself, except in the XML case when a user could + * declare a constraint for a specific subclass. + */ + private final Class declaringClass; + + public JavaBeanGetter(Method method) { + super( method ); + this.name = ReflectionHelper.getPropertyName( method ); + this.declaringClass = method.getDeclaringClass(); + } + + public JavaBeanGetter(Class declaringClass, Method method) { + super( method ); + this.name = ReflectionHelper.getPropertyName( method ); + this.declaringClass = declaringClass; + } + + @Override + public String getPropertyName() { + return name; + } + + @Override + public boolean hasReturnValue() { + // getters should always have a return value + return true; + } + + @Override + public boolean hasParameters() { + // getters should never have parameters + return false; + } + + @Override + public String getParameterName(ExecutableParameterNameProvider parameterNameProvider, int parameterIndex) { + throw new IllegalStateException( "Getters may not have parameters" ); + } + + @Override + public Class getDeclaringClass() { + return declaringClass; + } + + @Override + public ConstrainedElementKind getConstrainedElementKind() { + return ConstrainedElementKind.GETTER; + } + + @Override + public PropertyAccessor createAccessor() { + return new GetterAccessor( executable ); + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || this.getClass() != o.getClass() ) { + return false; + } + if ( !super.equals( o ) ) { + return false; + } + + JavaBeanGetter that = (JavaBeanGetter) o; + + return this.name.equals( that.name ); + } + + @Override + public int hashCode() { + int result = super.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/JavaBeanMethod.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanMethod.java new file mode 100644 index 0000000000..166af53e8d --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanMethod.java @@ -0,0 +1,32 @@ +/* + * 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.lang.reflect.Method; +import java.lang.reflect.TypeVariable; + +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind; + +/** + * @author Guillaume Smet + */ +public class JavaBeanMethod extends JavaBeanExecutable { + + JavaBeanMethod(Method method) { + super( method, method.getGenericReturnType() != void.class ); + } + + @Override + public ConstrainedElementKind getConstrainedElementKind() { + return ConstrainedElementKind.METHOD; + } + + @Override + public TypeVariable[] getTypeParameters() { + return executable.getReturnType().getTypeParameters(); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java new file mode 100644 index 0000000000..aae74c8e8d --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/JavaBeanParameter.java @@ -0,0 +1,68 @@ +/* + * 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.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; + +/** + * @author Guillaume Smet + */ +public class JavaBeanParameter implements JavaBeanAnnotatedElement { + + private final int index; + + private final Parameter parameter; + + private final Class type; + + private final Type genericType; + + JavaBeanParameter(int index, Parameter parameter, Class type, Type genericType) { + this.index = index; + this.parameter = parameter; + this.type = type; + this.genericType = genericType; + } + + public int getIndex() { + return index; + } + + @Override + public Class getType() { + return type; + } + + @Override + public AnnotatedType getAnnotatedType() { + return parameter.getAnnotatedType(); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return parameter.getDeclaredAnnotations(); + } + + @Override + public Type getGenericType() { + return genericType; + } + + @Override + public TypeVariable[] getTypeParameters() { + return parameter.getType().getTypeParameters(); + } + + @Override + public A getAnnotation(Class annotationClass) { + return parameter.getAnnotation( annotationClass ); + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/package-info.java b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/package-info.java new file mode 100644 index 0000000000..410921fdeb --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/properties/javabean/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; diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/Contracts.java b/engine/src/main/java/org/hibernate/validator/internal/util/Contracts.java index dc57395795..b7164465c6 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/util/Contracts.java +++ b/engine/src/main/java/org/hibernate/validator/internal/util/Contracts.java @@ -75,7 +75,7 @@ public static void assertTrue(boolean condition, String message, Object... messa } public static void assertNotEmpty(String s, String message) { - if ( s.length() == 0 ) { + if ( StringHelper.isNullOrEmptyString( s ) ) { throw LOG.getIllegalArgumentException( message ); } } diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/ExecutableHelper.java b/engine/src/main/java/org/hibernate/validator/internal/util/ExecutableHelper.java index 0ae6378a5a..cd5e1247a6 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/util/ExecutableHelper.java +++ b/engine/src/main/java/org/hibernate/validator/internal/util/ExecutableHelper.java @@ -17,6 +17,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.classhierarchy.Filters; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; @@ -46,6 +47,10 @@ public ExecutableHelper(TypeResolutionHelper typeResolutionHelper) { this.typeResolver = typeResolutionHelper.getTypeResolver(); } + public boolean overrides(Callable subTypeMethod, Callable superTypeMethod) { + return subTypeMethod.overrides( this, superTypeMethod ); + } + /** * Checks, whether {@code subTypeMethod} overrides {@code superTypeMethod}. * 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 d0cba30970..7a0da1e309 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 @@ -48,6 +48,9 @@ import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.raw.ConstrainedElement; +import org.hibernate.validator.internal.properties.Callable; +import org.hibernate.validator.internal.properties.Constrainable; import org.hibernate.validator.internal.util.logging.formatter.ArrayOfClassesObjectFormatter; import org.hibernate.validator.internal.util.logging.formatter.ClassObjectFormatter; import org.hibernate.validator.internal.util.logging.formatter.CollectionOfClassesObjectFormatter; @@ -60,6 +63,7 @@ import org.hibernate.validator.spi.scripting.ScriptEvaluationException; import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory; import org.hibernate.validator.spi.scripting.ScriptEvaluatorNotFoundException; + import org.jboss.logging.BasicLogger; import org.jboss.logging.annotations.Cause; import org.jboss.logging.annotations.FormatWith; @@ -248,14 +252,13 @@ GroupDefinitionException getUnableToExpandDefaultGroupListException(@FormatWith( GroupDefinitionException getWrongDefaultGroupSequenceProviderTypeException(@FormatWith(ClassObjectFormatter.class) Class beanClass); @Message(id = 56, value = "Method or constructor %1$s doesn't have a parameter with index %2$d.") - IllegalArgumentException getInvalidExecutableParameterIndexException(@FormatWith(ExecutableFormatter.class) Executable executable, int index); + IllegalArgumentException getInvalidExecutableParameterIndexException(Callable callable, int index); @Message(id = 59, value = "Unable to retrieve annotation parameter value.") ValidationException getUnableToRetrieveAnnotationParameterValueException(@Cause Exception e); - @Message(id = 62, - value = "Method or constructor %1$s has %2$s parameters, but the passed list of parameter meta data has a size of %3$s.") - IllegalArgumentException getInvalidLengthOfParameterMetaDataListException(@FormatWith(ExecutableFormatter.class) Executable executable, int nbParameters, int listSize); + @Message(id = 62, value = "Method or constructor %1$s has %2$s parameters, but the passed list of parameter meta data has a size of %3$s.") + IllegalArgumentException getInvalidLengthOfParameterMetaDataListException(Callable callable, int nbParameters, int listSize); @Message(id = 63, value = "Unable to instantiate %s.") ValidationException getUnableToInstantiateException(@FormatWith(ClassObjectFormatter.class) Class clazz, @Cause Exception e); @@ -461,11 +464,11 @@ ConstraintDeclarationException getMultipleGroupConversionsForSameSourceException @Message(id = 131, value = "A method return value must not be marked for cascaded validation more than once in a class hierarchy, but the following two methods are marked as such: %s, %s.") - ConstraintDeclarationException getMethodReturnValueMustNotBeMarkedMoreThanOnceForCascadedValidationException(@FormatWith(ExecutableFormatter.class) Executable executable1, @FormatWith(ExecutableFormatter.class) Executable executable2); + ConstraintDeclarationException getMethodReturnValueMustNotBeMarkedMoreThanOnceForCascadedValidationException(Callable callable1, Callable callable2); @Message(id = 132, value = "Void methods must not be constrained or marked for cascaded validation, but method %s is.") - ConstraintDeclarationException getVoidMethodsMustNotBeConstrainedException(@FormatWith(ExecutableFormatter.class) Executable executable); + ConstraintDeclarationException getVoidMethodsMustNotBeConstrainedException(Callable callable); @Message(id = 133, value = "%1$s does not contain a constructor with the parameter types %2$s.") ValidationException getBeanDoesNotContainConstructorException(@FormatWith(ClassObjectFormatter.class) Class beanClass, @@ -500,7 +503,7 @@ ConstraintDeclarationException getImplicitConstraintTargetInAmbiguousConfigurati @Message(id = 142, value = "Cross parameter constraint %1$s is illegally placed on a parameterless method or constructor '%2$s'.") ConstraintDeclarationException getCrossParameterConstraintOnMethodWithoutParametersException( - @FormatWith(ClassObjectFormatter.class) Class constraint, @FormatWith(ExecutableFormatter.class) Executable executable); + @FormatWith(ClassObjectFormatter.class) Class constraint, Constrainable executable); @Message(id = 143, value = "Cross parameter constraint %1$s is illegally placed on class level.") @@ -509,7 +512,7 @@ ConstraintDeclarationException getCrossParameterConstraintOnMethodWithoutParamet @Message(id = 144, value = "Cross parameter constraint %1$s is illegally placed on field '%2$s'.") ConstraintDeclarationException getCrossParameterConstraintOnFieldException(@FormatWith(ClassObjectFormatter.class) Class constraint, - Member field); + Constrainable field); @Message(id = 146, value = "No parameter nodes may be added since path %s doesn't refer to a cross-parameter constraint.") @@ -535,11 +538,11 @@ UnexpectedTypeException getMultipleValidatorsForSameTypeException(@FormatWith(Cl @Message(id = 151, value = "A method overriding another method must not redefine the parameter constraint configuration, but method %2$s redefines the configuration of %1$s.") - ConstraintDeclarationException getParameterConfigurationAlteredInSubTypeException(@FormatWith(ExecutableFormatter.class) Executable superMethod, @FormatWith(ExecutableFormatter.class) Executable subMethod); + ConstraintDeclarationException getParameterConfigurationAlteredInSubTypeException(Callable superMethod, Callable subMethod); @Message(id = 152, value = "Two methods defined in parallel types must not declare parameter constraints, if they are overridden by the same method, but methods %s and %s both define parameter constraints.") - ConstraintDeclarationException getParameterConstraintsDefinedInMethodsFromParallelTypesException(@FormatWith(ExecutableFormatter.class) Executable method1, @FormatWith(ExecutableFormatter.class) Executable method2); + ConstraintDeclarationException getParameterConstraintsDefinedInMethodsFromParallelTypesException(Callable method1, Callable method2); @Message(id = 153, value = "The constraint %1$s used ConstraintTarget#%2$s but is not specified on a method or constructor.") @@ -581,7 +584,7 @@ ConstraintDefinitionException getValidatorForCrossParameterConstraintMustEitherV @Message(id = 161, value = "Two methods defined in parallel types must not define group conversions for a cascaded method return value, if they are overridden by the same method, but methods %s and %s both define parameter constraints.") - ConstraintDeclarationException getMethodsFromParallelTypesMustNotDefineGroupConversionsForCascadedReturnValueException(@FormatWith(ExecutableFormatter.class) Executable method1, @FormatWith(ExecutableFormatter.class) Executable method2); + ConstraintDeclarationException getMethodsFromParallelTypesMustNotDefineGroupConversionsForCascadedReturnValueException(Callable method1, Callable method2); @Message(id = 162, value = "The validated type %1$s does not specify the constructor/method: %2$s") @@ -625,15 +628,15 @@ ConstraintDefinitionException getValidatorForCrossParameterConstraintMustEitherV @Message(id = 173, value = "Method %2$s of type %1$s is configured more than once via the programmatic constraint declaration API.") - ValidationException getMethodHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, String method); + ValidationException getMethodHasAlreadyBeenConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, String method); @Message(id = 174, value = "Parameter %3$s of method or constructor %2$s of type %1$s is configured more than once via the programmatic constraint declaration API.") - ValidationException getParameterHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, @FormatWith(ExecutableFormatter.class) Executable executable, int parameterIndex); + ValidationException getParameterHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, Callable callable, int parameterIndex); @Message(id = 175, value = "The return value of method or constructor %2$s of type %1$s is configured more than once via the programmatic constraint declaration API.") - ValidationException getReturnValueHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, @FormatWith(ExecutableFormatter.class) Executable executable); + ValidationException getReturnValueHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, Callable callable); @Message(id = 176, value = "Constructor %2$s of type %1$s is configured more than once via the programmatic constraint declaration API.") @@ -641,7 +644,7 @@ ConstraintDefinitionException getValidatorForCrossParameterConstraintMustEitherV @Message(id = 177, value = "Cross-parameter constraints for the method or constructor %2$s of type %1$s are declared more than once via the programmatic constraint declaration API.") - ValidationException getCrossParameterElementHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, @FormatWith(ExecutableFormatter.class) Executable executable); + ValidationException getCrossParameterElementHasAlreadyBeConfiguredViaProgrammaticApiException(@FormatWith(ClassObjectFormatter.class) Class beanClass, Callable callable); @Message(id = 178, value = "Multiplier cannot be negative: %d.") IllegalArgumentException getMultiplierCannotBeNegativeException(int multiplier); @@ -714,7 +717,7 @@ ConstraintDeclarationException getInconsistentValueUnwrappingConfigurationBetwee ValueExtractorDefinitionException getValueExtractorDeclaresExtractedValueMultipleTimesException(@FormatWith(ClassObjectFormatter.class) Class extractorType); @Message(id = 205, value = "Invalid unwrapping configuration for constraint %2$s on %1$s. You can only define one of 'Unwrapping.Skip' or 'Unwrapping.Unwrap'.") - ConstraintDeclarationException getInvalidUnwrappingConfigurationForConstraintException(Member member, @FormatWith(ClassObjectFormatter.class) Class constraint); + ConstraintDeclarationException getInvalidUnwrappingConfigurationForConstraintException(Constrainable constrainable, @FormatWith(ClassObjectFormatter.class) Class constraint); @Message(id = 206, value = "Unable to instantiate value extractor class %s.") ValidationException getUnableToInstantiateValueExtractorClassException(String valueExtractorClassName, @Cause ValidationException e); @@ -855,4 +858,10 @@ ConstraintDefinitionException getConstraintValidatorDefinitionConstraintMismatch @FormatWith(ClassObjectFormatter.class) Class> constraintValidatorImplementationType, @FormatWith(ClassObjectFormatter.class) Class registeredConstraintAnnotationType, @FormatWith(TypeFormatter.class) Type declaredConstraintAnnotationType); + + @Message(id = 244, value = "ConstrainedElement expected class was %1$s, but instead received %2$s.") + AssertionError getUnexpectedConstraintElementType(@FormatWith(ClassObjectFormatter.class) Class expecting, @FormatWith(ClassObjectFormatter.class) Class got); + + @Message(id = 245, value = "Allowed constraint element types are FIELD and GETTER, but instead received %1$s.") + AssertionError getUnsupportedConstraintElementType(ConstrainedElement.ConstrainedElementKind kind); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ClassConstraintTypeStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ClassConstraintTypeStaxBuilder.java index c75a851b14..1d059154eb 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ClassConstraintTypeStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ClassConstraintTypeStaxBuilder.java @@ -24,6 +24,7 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; import org.hibernate.validator.internal.util.TypeResolutionHelper; @@ -103,7 +104,7 @@ ConstrainedType build(Class beanClass) { ConstraintLocation constraintLocation = ConstraintLocation.forClass( beanClass ); Set> metaConstraints = constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, java.lang.annotation.ElementType.TYPE, null ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.TYPE, null ) ) .collect( Collectors.toSet() ); // ignore annotation diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedConstructorStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedConstructorStaxBuilder.java index d29312b7b8..dd8da3e3e3 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedConstructorStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedConstructorStaxBuilder.java @@ -26,6 +26,7 @@ import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; +import org.hibernate.validator.internal.properties.javabean.JavaBeanConstructor; import org.hibernate.validator.internal.util.CollectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -85,6 +86,8 @@ ConstrainedExecutable build(Class beanClass, List> alreadyProc ); } + JavaBeanConstructor javaBeanConstructor = new JavaBeanConstructor( constructor ); + if ( alreadyProcessedConstructors.contains( constructor ) ) { throw LOG.getConstructorIsDefinedTwiceInMappingXmlForBeanException( constructor, beanClass ); } @@ -95,7 +98,7 @@ ConstrainedExecutable build(Class beanClass, List> alreadyProc // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsOnMember( - constructor, + javaBeanConstructor, ignoreAnnotations.get() ); } @@ -103,21 +106,22 @@ ConstrainedExecutable build(Class beanClass, List> alreadyProc List constrainedParameters = CollectionHelper.newArrayList( constrainedParameterStaxBuilders.size() ); for ( int index = 0; index < constrainedParameterStaxBuilders.size(); index++ ) { ConstrainedParameterStaxBuilder builder = constrainedParameterStaxBuilders.get( index ); - constrainedParameters.add( builder.build( constructor, index ) ); + constrainedParameters.add( builder.build( javaBeanConstructor, index ) ); } Set> crossParameterConstraints = getCrossParameterStaxBuilder() - .map( builder -> builder.build( constructor ) ).orElse( Collections.emptySet() ); + .map( builder -> builder.build( javaBeanConstructor ) ).orElse( Collections.emptySet() ); // parse the return value Set> returnValueConstraints = new HashSet<>(); Set> returnValueTypeArgumentConstraints = new HashSet<>(); - CascadingMetaDataBuilder cascadingMetaDataBuilder = getReturnValueStaxBuilder().map( builder -> builder.build( constructor, returnValueConstraints, returnValueTypeArgumentConstraints ) ) + CascadingMetaDataBuilder cascadingMetaDataBuilder = getReturnValueStaxBuilder() + .map( builder -> builder.build( javaBeanConstructor, returnValueConstraints, returnValueTypeArgumentConstraints ) ) .orElse( CascadingMetaDataBuilder.nonCascading() ); return new ConstrainedExecutable( ConfigurationSource.XML, - constructor, + javaBeanConstructor, constrainedParameters, crossParameterConstraints, returnValueConstraints, 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 8b2a8a97be..bb0a350084 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 @@ -22,8 +22,10 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; 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.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -69,17 +71,19 @@ ConstrainedField build(Class beanClass, List alreadyProcessedFieldNam alreadyProcessedFieldNames.add( mainAttributeValue ); } Field field = findField( beanClass, mainAttributeValue ); - ConstraintLocation constraintLocation = ConstraintLocation.forField( field ); + JavaBeanField javaBeanField = new JavaBeanField( field ); + ConstraintLocation constraintLocation = ConstraintLocation.forField( javaBeanField ); + Set> metaConstraints = constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, java.lang.annotation.ElementType.FIELD, null ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.FIELD, null ) ) .collect( Collectors.toSet() ); ContainerElementTypeConfiguration containerElementTypeConfiguration = getContainerElementTypeConfiguration( - ReflectionHelper.typeOf( field ), constraintLocation ); + javaBeanField.getType(), constraintLocation ); ConstrainedField constrainedField = new ConstrainedField( ConfigurationSource.XML, - field, + javaBeanField, metaConstraints, containerElementTypeConfiguration.getMetaConstraints(), getCascadingMetaData( containerElementTypeConfiguration.getTypeParametersCascadingMetaData(), ReflectionHelper.typeOf( field ) ) @@ -88,7 +92,7 @@ ConstrainedField build(Class beanClass, List alreadyProcessedFieldNam // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsOnMember( - field, + javaBeanField, ignoreAnnotations.get() ); } 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 ba1b607ffd..3969c10577 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 @@ -23,9 +23,11 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; 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.util.ReflectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -71,10 +73,11 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedGet alreadyProcessedGetterNames.add( mainAttributeValue ); } Method getter = findGetter( beanClass, mainAttributeValue ); - ConstraintLocation constraintLocation = ConstraintLocation.forGetter( beanClass, getter ); + JavaBeanGetter javaBeanGetter = new JavaBeanGetter( beanClass, getter ); + ConstraintLocation constraintLocation = ConstraintLocation.forGetter( javaBeanGetter ); Set> metaConstraints = constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, java.lang.annotation.ElementType.METHOD, null ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.GETTER, null ) ) .collect( Collectors.toSet() ); ContainerElementTypeConfiguration containerElementTypeConfiguration = getContainerElementTypeConfiguration( @@ -82,7 +85,7 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedGet ConstrainedExecutable constrainedGetter = new ConstrainedExecutable( ConfigurationSource.XML, - getter, + javaBeanGetter, Collections.emptyList(), Collections.>emptySet(), metaConstraints, @@ -93,7 +96,7 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedGet // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsOnMember( - getter, + javaBeanGetter, ignoreAnnotations.get() ); } 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 ede789a730..4a78d244bc 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 @@ -26,6 +26,7 @@ import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; 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.util.CollectionHelper; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -96,11 +97,12 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedMet else { alreadyProcessedMethods.add( method ); } + JavaBeanExecutable executable = JavaBeanExecutable.of( method ); // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsOnMember( - method, + executable, ignoreAnnotations.get() ); } @@ -108,21 +110,21 @@ ConstrainedExecutable build(Class beanClass, List alreadyProcessedMet List constrainedParameters = CollectionHelper.newArrayList( constrainedParameterStaxBuilders.size() ); for ( int index = 0; index < constrainedParameterStaxBuilders.size(); index++ ) { ConstrainedParameterStaxBuilder builder = constrainedParameterStaxBuilders.get( index ); - constrainedParameters.add( builder.build( method, index ) ); + constrainedParameters.add( builder.build( executable, index ) ); } Set> crossParameterConstraints = getCrossParameterStaxBuilder() - .map( builder -> builder.build( method ) ).orElse( Collections.emptySet() ); + .map( builder -> builder.build( executable ) ).orElse( Collections.emptySet() ); // parse the return value Set> returnValueConstraints = new HashSet<>(); Set> returnValueTypeArgumentConstraints = new HashSet<>(); - CascadingMetaDataBuilder cascadingMetaDataBuilder = getReturnValueStaxBuilder().map( builder -> builder.build( method, returnValueConstraints, returnValueTypeArgumentConstraints ) ) + CascadingMetaDataBuilder cascadingMetaDataBuilder = getReturnValueStaxBuilder().map( builder -> builder.build( executable, returnValueConstraints, returnValueTypeArgumentConstraints ) ) .orElse( CascadingMetaDataBuilder.nonCascading() ); return new ConstrainedExecutable( ConfigurationSource.XML, - method, + executable, constrainedParameters, crossParameterConstraints, returnValueConstraints, diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedParameterStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedParameterStaxBuilder.java index cf5a77d690..5cc0cb2f65 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedParameterStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstrainedParameterStaxBuilder.java @@ -7,7 +7,6 @@ package org.hibernate.validator.internal.xml.mapping; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Executable; import java.lang.reflect.Type; import java.util.Optional; import java.util.Set; @@ -21,9 +20,10 @@ import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter; -import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; @@ -68,13 +68,13 @@ public Class getParameterType(Class beanClass) { } } - ConstrainedParameter build(Executable executable, int index) { + ConstrainedParameter build(Callable callable, int index) { - ConstraintLocation constraintLocation = ConstraintLocation.forParameter( executable, index ); - Type type = ReflectionHelper.typeOf( executable, index ); + ConstraintLocation constraintLocation = ConstraintLocation.forParameter( callable, index ); + Type type = callable.getParameterGenericType( index ); Set> metaConstraints = constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, java.lang.annotation.ElementType.PARAMETER, null ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.PARAMETER, null ) ) .collect( Collectors.toSet() ); ContainerElementTypeConfiguration containerElementTypeConfiguration = getContainerElementTypeConfiguration( type, constraintLocation ); @@ -82,7 +82,7 @@ ConstrainedParameter build(Executable executable, int index) { // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsOnParameter( - executable, + callable, index, ignoreAnnotations.get() ); @@ -90,7 +90,7 @@ ConstrainedParameter build(Executable executable, int index) { ConstrainedParameter constrainedParameter = new ConstrainedParameter( ConfigurationSource.XML, - executable, + callable, type, index, metaConstraints, diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintTypeStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintTypeStaxBuilder.java index 862a1226ad..10557668cb 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintTypeStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ConstraintTypeStaxBuilder.java @@ -35,6 +35,7 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraints; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.annotation.AnnotationDescriptor; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; @@ -112,7 +113,7 @@ protected void add(XMLEventReader xmlEventReader, XMLEvent xmlEvent) throws XMLS } @SuppressWarnings("unchecked") - MetaConstraint build(ConstraintLocation constraintLocation, java.lang.annotation.ElementType type, ConstraintDescriptorImpl.ConstraintType constraintType) { + MetaConstraint build(ConstraintLocation constraintLocation, ConstraintLocationKind kind, ConstraintDescriptorImpl.ConstraintType constraintType) { String defaultPackage = defaultPackageStaxBuilder.build().orElse( "" ); Class annotationClass; @@ -148,8 +149,8 @@ MetaConstraint build(ConstraintLocation constraintLoca // we set initially ConstraintOrigin.DEFINED_LOCALLY for all xml configured constraints // later we will make copies of this constraint descriptor when needed and adjust the ConstraintOrigin - ConstraintDescriptorImpl constraintDescriptor = new ConstraintDescriptorImpl( - constraintHelper, constraintLocation.getMember(), annotationDescriptor, type, constraintType + ConstraintDescriptorImpl constraintDescriptor = new ConstraintDescriptorImpl<>( + constraintHelper, constraintLocation.getConstrainable(), annotationDescriptor, kind, constraintType ); return MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor, constraintLocation ); diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ContainerElementTypeStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ContainerElementTypeStaxBuilder.java index 1c24591a22..eeb2d16a6d 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ContainerElementTypeStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ContainerElementTypeStaxBuilder.java @@ -163,7 +163,7 @@ public ContainerElementTypeConfiguration build(Set con .map( builder -> builder.build( containerElementTypeConstraintLocation, - java.lang.annotation.ElementType.TYPE_USE, + ConstraintLocation.ConstraintLocationKind.TYPE_USE, null ) ), diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/CrossParameterStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/CrossParameterStaxBuilder.java index 30397e1009..84119ecbd3 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/CrossParameterStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/CrossParameterStaxBuilder.java @@ -6,7 +6,6 @@ */ package org.hibernate.validator.internal.xml.mapping; -import java.lang.reflect.Executable; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -24,6 +23,8 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.xml.AbstractStaxBuilder; @@ -83,18 +84,19 @@ private ConstraintTypeStaxBuilder getNewConstraintTypeStaxBuilder() { return new ConstraintTypeStaxBuilder( classLoadingHelper, constraintHelper, typeResolutionHelper, valueExtractorManager, defaultPackageStaxBuilder ); } - Set> build(Executable executable) { + Set> build(Callable callable) { - ConstraintLocation constraintLocation = ConstraintLocation.forCrossParameter( executable ); + ConstraintLocation constraintLocation = ConstraintLocation.forCrossParameter( callable ); Set> crossParameterConstraints = constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, java.lang.annotation.ElementType.METHOD, ConstraintType.CROSS_PARAMETER ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.of( callable.getConstrainedElementKind() ), + ConstraintType.CROSS_PARAMETER ) ) .collect( Collectors.toSet() ); // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsForCrossParameterConstraint( - executable, + callable, ignoreAnnotations.get() ); } diff --git a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ReturnValueStaxBuilder.java b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ReturnValueStaxBuilder.java index 85cae903e2..8157a2ba6d 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ReturnValueStaxBuilder.java +++ b/engine/src/main/java/org/hibernate/validator/internal/xml/mapping/ReturnValueStaxBuilder.java @@ -6,7 +6,6 @@ */ package org.hibernate.validator.internal.xml.mapping; -import java.lang.reflect.Executable; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -20,8 +19,8 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraint; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; -import org.hibernate.validator.internal.util.ExecutableHelper; -import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; +import org.hibernate.validator.internal.properties.Callable; import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.internal.xml.mapping.ContainerElementTypeConfigurationBuilder.ContainerElementTypeConfiguration; @@ -51,27 +50,28 @@ protected String getAcceptableQName() { } CascadingMetaDataBuilder build( - Executable executable, + Callable callable, Set> returnValueConstraints, Set> returnValueTypeArgumentConstraints) { - ConstraintLocation constraintLocation = ConstraintLocation.forReturnValue( executable ); + ConstraintLocation constraintLocation = ConstraintLocation.forReturnValue( callable ); returnValueConstraints.addAll( constraintTypeStaxBuilders.stream() - .map( builder -> builder.build( constraintLocation, ExecutableHelper.getElementType( executable ), ConstraintDescriptorImpl.ConstraintType.GENERIC ) ) + .map( builder -> builder.build( constraintLocation, ConstraintLocationKind.of( callable.getConstrainedElementKind() ), + ConstraintDescriptorImpl.ConstraintType.GENERIC ) ) .collect( Collectors.toSet() ) ); - ContainerElementTypeConfiguration containerElementTypeConfiguration = getContainerElementTypeConfiguration( ReflectionHelper.typeOf( executable ), constraintLocation ); + ContainerElementTypeConfiguration containerElementTypeConfiguration = getContainerElementTypeConfiguration( callable.getType(), constraintLocation ); returnValueTypeArgumentConstraints.addAll( containerElementTypeConfiguration.getMetaConstraints() ); // ignore annotations if ( ignoreAnnotations.isPresent() ) { annotationProcessingOptions.ignoreConstraintAnnotationsForReturnValue( - executable, + callable, ignoreAnnotations.get() ); } - return getCascadingMetaData( containerElementTypeConfiguration.getTypeParametersCascadingMetaData(), ReflectionHelper.typeOf( executable ) ); + return getCascadingMetaData( containerElementTypeConfiguration.getTypeParametersCascadingMetaData(), callable.getType() ); } } diff --git a/engine/src/test/java/org/hibernate/validator/test/cfg/ConstraintMappingTest.java b/engine/src/test/java/org/hibernate/validator/test/cfg/ConstraintMappingTest.java index d0fc924caa..d1924b6bfb 100644 --- a/engine/src/test/java/org/hibernate/validator/test/cfg/ConstraintMappingTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/cfg/ConstraintMappingTest.java @@ -60,6 +60,7 @@ import org.hibernate.validator.internal.util.TypeResolutionHelper; import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider; import org.hibernate.validator.testutils.ValidatorUtil; + import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -535,6 +536,28 @@ public void testProgrammaticAndAnnotationPropertyConstraintsAddUp() { ); } + @Test + public void testFieldAndGetterMethodsForProgrammaticConstraintDefinition() { + mapping.type( Marathon.class ) + .getter( "name" ) + .constraint( new SizeDef().min( 5 ) ) + .constraint( new SizeDef().min( 10 ) ) + .field( "runners" ) + .constraint( new SizeDef().max( 10 ).min( 1 ) ); + config.addMapping( mapping ); + Validator validator = config.buildValidatorFactory().getValidator(); + + Marathon marathon = new Marathon(); + marathon.setName( "Foo" ); + + Set> violations = validator.validate( marathon ); + assertThat( violations ).containsOnlyViolations( + violationOf( Size.class ).withMessage( "size must be between 10 and 2147483647" ), + violationOf( Size.class ).withMessage( "size must be between 5 and 2147483647" ), + violationOf( Size.class ).withMessage( "size must be between 1 and 10" ) + ); + } + private BeanConfiguration getBeanConfiguration(Class type) { Set> beanConfigurations = mapping.getBeanConfigurations( new ConstraintHelper(), @@ -556,7 +579,7 @@ private BeanConfiguration getBeanConfiguration(Class type) { private ConstrainedField getConstrainedField(BeanConfiguration beanConfiguration, String fieldName) { for ( ConstrainedElement constrainedElement : beanConfiguration.getConstrainedElements() ) { if ( constrainedElement.getKind() == ConstrainedElementKind.FIELD && - ( (ConstrainedField) constrainedElement ).getField().getName().equals( fieldName ) ) { + ( (ConstrainedField) constrainedElement ).getField().getPropertyName().equals( fieldName ) ) { return (ConstrainedField) constrainedElement; } } @@ -566,8 +589,8 @@ private ConstrainedField getConstrainedField(BeanConfiguration beanConfigurat private ConstrainedExecutable getConstrainedExecutable(BeanConfiguration beanConfiguration, String executableName) { for ( ConstrainedElement constrainedElement : beanConfiguration.getConstrainedElements() ) { - if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD && - ( (ConstrainedExecutable) constrainedElement ).getExecutable().getName().equals( executableName ) ) { + if ( constrainedElement.getKind().isMethod() && + ( (ConstrainedExecutable) constrainedElement ).getCallable().getName().equals( executableName ) ) { return (ConstrainedExecutable) constrainedElement; } } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/failfast/FailFastTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/failfast/FailFastTest.java index 1098e29f1f..29721e713f 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/failfast/FailFastTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/failfast/FailFastTest.java @@ -162,8 +162,9 @@ public void testFailFastMethodValidationSetOnValidatorFactory() { fail(); } catch (ConstraintViolationException e) { - assertThat( e.getConstraintViolations() ).containsOnlyViolations( - violationOf( NotBlank.class ) + assertThat( e.getConstraintViolations() ).containsOneOfViolations( + violationOf( NotBlank.class ), + violationOf( Min.class ) ); } } @@ -212,8 +213,9 @@ public void testFailFastMethodValidationSetWithProperty() { fail(); } catch (ConstraintViolationException e) { - assertThat( e.getConstraintViolations() ).containsOnlyViolations( - violationOf( NotBlank.class ) + assertThat( e.getConstraintViolations() ).containsOneOfViolations( + violationOf( NotBlank.class ), + violationOf( Min.class ) ); } } diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ExpressionLanguageMessageInterpolationTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ExpressionLanguageMessageInterpolationTest.java index b9515ff476..c869c51c9b 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ExpressionLanguageMessageInterpolationTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ExpressionLanguageMessageInterpolationTest.java @@ -18,6 +18,7 @@ import org.hibernate.validator.internal.engine.MessageInterpolatorContext; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; import org.hibernate.validator.testutil.TestForIssue; @@ -44,7 +45,7 @@ public void setUp() { new ConstraintHelper(), null, notNullAnnotationDescriptorBuilder.build(), - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); ConstraintAnnotationDescriptor.Builder sizeAnnotationDescriptorBuilder = new ConstraintAnnotationDescriptor.Builder<>( Size.class ); @@ -52,7 +53,7 @@ public void setUp() { new ConstraintHelper(), null, sizeAnnotationDescriptorBuilder.build(), - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); interpolatorUnderTest = new ResourceBundleMessageInterpolator(); diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java index 889120f615..29bdf5ff3a 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java @@ -27,6 +27,7 @@ import org.hibernate.validator.internal.engine.MessageInterpolatorContext; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator; @@ -54,7 +55,7 @@ public void setUp() { new ConstraintHelper(), null, descriptorBuilder.build(), - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); ConstraintAnnotationDescriptor.Builder sizeAnnotationDescriptorBuilder = new ConstraintAnnotationDescriptor.Builder( Size.class ); @@ -62,7 +63,7 @@ public void setUp() { new ConstraintHelper(), null, sizeAnnotationDescriptorBuilder.build(), - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); } @@ -216,7 +217,7 @@ public void testRecursiveMessageInterpolation() { new ConstraintHelper(), null, descriptorBuilder.build(), - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); interpolator = new ResourceBundleMessageInterpolator( @@ -245,7 +246,7 @@ public void testCorrectMessageInterpolationIfParameterCannotBeReplaced() { new ConstraintHelper(), null, maxDescriptor, - java.lang.annotation.ElementType.FIELD + ConstraintLocationKind.FIELD ); interpolator = new ResourceBundleMessageInterpolator( 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 29cfcc5550..436f7e8b3a 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 @@ -6,7 +6,6 @@ */ package org.hibernate.validator.test.internal.metadata.core; -import static java.lang.annotation.ElementType.METHOD; import static org.testng.Assert.assertEquals; import java.lang.reflect.Method; @@ -20,9 +19,12 @@ import org.hibernate.validator.internal.metadata.core.MetaConstraints; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; 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.util.TypeResolutionHelper; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.testutil.TestForIssue; + import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -49,14 +51,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, barMethod, constraintAnnotationDescriptor, METHOD + constraintHelper, JavaBeanExecutable.of( barMethod ), constraintAnnotationDescriptor, ConstraintLocationKind.METHOD ); ConstraintLocation location1 = ConstraintLocation.forClass( Foo.class ); MetaConstraint metaConstraint1 = MetaConstraints.create( typeResolutionHelper, valueExtractorManager, constraintDescriptor1, location1 ); ConstraintDescriptorImpl constraintDescriptor2 = new ConstraintDescriptorImpl<>( - constraintHelper, barMethod, constraintAnnotationDescriptor, METHOD + constraintHelper, JavaBeanExecutable.of( 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 8e424bbd4a..0bbca776e3 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 @@ -11,6 +11,7 @@ import java.lang.reflect.Method; import org.hibernate.validator.internal.metadata.location.ConstraintLocation; +import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter; import org.hibernate.validator.testutil.TestForIssue; import org.testng.annotations.Test; @@ -32,8 +33,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( getter ); - ConstraintLocation location2 = ConstraintLocation.forGetter( getter ); + ConstraintLocation location1 = ConstraintLocation.forGetter( new JavaBeanGetter( getter ) ); + ConstraintLocation location2 = ConstraintLocation.forGetter( new JavaBeanGetter( 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 9953a487f8..47dc49bc44 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 @@ -12,7 +12,6 @@ import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -33,6 +32,7 @@ import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.core.MetaConstraint; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider; import org.hibernate.validator.internal.metadata.raw.BeanConfiguration; import org.hibernate.validator.internal.metadata.raw.ConfigurationSource; @@ -40,8 +40,10 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; 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.util.TypeResolutionHelper; import org.hibernate.validator.testutil.TestForIssue; + import org.joda.time.DateMidnight; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -78,7 +80,7 @@ public void testGetConstructorMetaData() throws Exception { MetaConstraint constraint = constructor.getConstraints().iterator().next(); assertThat( constraint.getDescriptor().getAnnotation().annotationType() ).isEqualTo( NotNull.class ); - assertThat( constraint.getElementType() ).isEqualTo( ElementType.CONSTRUCTOR ); + assertThat( constraint.getConstraintLocationKind() ).isEqualTo( ConstraintLocationKind.CONSTRUCTOR ); } @Test @@ -101,11 +103,13 @@ public void testGetCrossParameterMetaData() throws Exception { assertThat( createEvent.getConstraints() ).as( "No return value constraints expected" ).isEmpty(); assertThat( createEvent.getCrossParameterConstraints() ).hasSize( 1 ); - assertThat( createEvent.getExecutable() ).isEqualTo( - Calendar.class.getMethod( - "createEvent", - DateMidnight.class, - DateMidnight.class + assertThat( createEvent.getCallable() ).isEqualTo( + JavaBeanExecutable.of( + Calendar.class.getMethod( + "createEvent", + DateMidnight.class, + DateMidnight.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 fca67eae25..bf6f716428 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 @@ -16,6 +16,9 @@ import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable; import org.hibernate.validator.internal.metadata.raw.ConstrainedField; import org.hibernate.validator.internal.metadata.raw.ConstrainedType; +import org.hibernate.validator.internal.properties.Constrainable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable; +import org.hibernate.validator.internal.properties.javabean.JavaBeanField; /** * @author Gunnar Morling @@ -59,14 +62,22 @@ protected ConstrainedType findConstrainedType(BeanConfiguration beanConfi protected ConstrainedElement findConstrainedElement(BeanConfiguration beanConfiguration, Member member) { + Constrainable constrainable; + if ( member instanceof Field ) { + constrainable = new JavaBeanField( (Field) member ); + } + else { + constrainable = JavaBeanExecutable.of( (Executable) member ); + } + for ( ConstrainedElement constrainedElement : beanConfiguration.getConstrainedElements() ) { if ( member instanceof Executable && constrainedElement instanceof ConstrainedExecutable ) { - if ( member.equals( ( (ConstrainedExecutable) constrainedElement ).getExecutable() ) ) { + if ( constrainable.equals( ( (ConstrainedExecutable) constrainedElement ).getCallable() ) ) { return constrainedElement; } } - else if ( member instanceof Field && constrainedElement instanceof ConstrainedField ) { - if ( member.equals( ( (ConstrainedField) constrainedElement ).getField() ) ) { + else if ( constrainedElement instanceof ConstrainedField ) { + if ( constrainable.equals( ( (ConstrainedField) constrainedElement ).getField() ) ) { return constrainedElement; } } diff --git a/engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java b/engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java index ea3e4b917d..30dbe909d4 100644 --- a/engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java +++ b/engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java @@ -18,6 +18,7 @@ import org.hibernate.validator.internal.engine.scripting.DefaultScriptEvaluatorFactory; import org.hibernate.validator.internal.metadata.core.ConstraintHelper; import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; +import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind; import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor; import org.hibernate.validator.spi.scripting.ScriptEvaluator; import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory; @@ -40,7 +41,7 @@ public static ConstraintDescriptor descriptorFrom(Cons CONSTRAINT_HELPER, null, annotationDescriptor, - null + ConstraintLocationKind.GETTER ); } diff --git a/test-utils/src/main/java/org/hibernate/validator/testutil/ConstraintViolationAssert.java b/test-utils/src/main/java/org/hibernate/validator/testutil/ConstraintViolationAssert.java index 1316865371..cf234f1bc7 100644 --- a/test-utils/src/main/java/org/hibernate/validator/testutil/ConstraintViolationAssert.java +++ b/test-utils/src/main/java/org/hibernate/validator/testutil/ConstraintViolationAssert.java @@ -263,6 +263,21 @@ public ConstraintViolationSetAssert describedAs(String description, Object... ar public void containsOnlyViolations(ViolationExpectation... expectedViolations) { isNotNull(); + List actualViolations = getActualViolationExpectations( expectedViolations ); + + Assertions.assertThat( actualViolations ).containsExactlyInAnyOrder( expectedViolations ); + } + + public void containsOneOfViolations(ViolationExpectation... expectedViolations) { + isNotNull(); + + List actualViolations = getActualViolationExpectations( expectedViolations ); + + Assertions.assertThat( actualViolations ).hasSize( 1 ); + Assertions.assertThat( expectedViolations ).contains( actualViolations.get( 0 ) ); + } + + private List getActualViolationExpectations(ViolationExpectation[] expectedViolations) { List actualViolations = new ArrayList<>(); ViolationExpectationPropertiesToTest referencePropertiesToTest; @@ -284,7 +299,7 @@ public void containsOnlyViolations(ViolationExpectation... expectedViolations) { actualViolations.add( new ViolationExpectation( violation, referencePropertiesToTest ) ); } - Assertions.assertThat( actualViolations ).containsExactlyInAnyOrder( expectedViolations ); + return actualViolations; } public void containsOnlyPaths(PathExpectation... paths) {