diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintTree.java b/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintTree.java index f993574e49..62eef1e276 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintTree.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintTree.java @@ -161,7 +161,7 @@ private void validateConstraints(ValidationContext executionContext, private boolean mainConstraintNeedsEvaluation(ValidationContext executionContext, Set> constraintViolations) { // there is no validator for the main constraints - if ( descriptor.getConstraintValidatorClasses().isEmpty() ) { + if ( descriptor.getApplyingConstraintValidatorClasses().isEmpty() ) { return false; } diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorManager.java b/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorManager.java index b1a94cbd30..cab3d0339c 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorManager.java +++ b/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorManager.java @@ -26,6 +26,7 @@ import javax.validation.ConstraintValidatorFactory; import javax.validation.metadata.ConstraintDescriptor; +import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.internal.util.Contracts; import org.hibernate.validator.internal.util.TypeHelper; import org.hibernate.validator.internal.util.logging.Log; @@ -76,7 +77,7 @@ public ConstraintValidatorManager(ConstraintValidatorFactory constraintValidator * @return A initialized constraint validator for the given type and annotation of the value to be validated. */ public ConstraintValidator getInitializedValidator(Type validatedValueType, - ConstraintDescriptor descriptor, + ConstraintDescriptorImpl descriptor, ConstraintValidatorFactory constraintFactory) { Contracts.assertNotNull( validatedValueType ); Contracts.assertNotNull( descriptor ); @@ -180,9 +181,9 @@ public int numberOfCachedConstraintValidatorInstances() { * * @return The class of a matching validator. */ - private Class> findMatchingValidatorClass(ConstraintDescriptor descriptor, Type validatedValueType) { + private Class> findMatchingValidatorClass(ConstraintDescriptorImpl descriptor, Type validatedValueType) { Map>> availableValidatorTypes = TypeHelper.getValidatorsTypes( - descriptor.getConstraintValidatorClasses() + descriptor.getApplyingConstraintValidatorClasses() ); List discoveredSuitableTypes = findSuitableValidatorTypes( validatedValueType, availableValidatorTypes ); 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 9c688f7b47..261df439d9 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 @@ -55,6 +55,7 @@ import org.hibernate.validator.internal.util.logging.LoggerFactory; import static org.hibernate.validator.constraints.CompositionType.AND; +import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList; import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap; import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; @@ -108,6 +109,8 @@ public class ConstraintDescriptorImpl implements Constrain */ private final Class> crossParameterConstraintValidatorClass; + private final List>> applyingConstraintValidatorClasses; + /** * The groups for which to apply this constraint. */ @@ -176,13 +179,27 @@ public ConstraintDescriptorImpl(T annotation, this.attributes = buildAnnotationParameterMap( annotation ); this.groups = buildGroupSet( implicitGroup ); this.payloads = buildPayloadSet( annotation ); + this.constraintValidatorDefinitionClasses = constraintHelper.getValidatorClasses( annotationType ); this.crossParameterConstraintValidatorClass = findCrossParameterValidatorClass( constraintValidatorDefinitionClasses ); + List>> genericValidatorClasses = findGenericValidatorClasses( + constraintValidatorDefinitionClasses + ); + this.constraintType = determineConstraintType( member ); this.composingConstraints = parseComposingConstraints( member, constraintHelper ); + + if ( constraintType == ConstraintType.GENERIC ) { + this.applyingConstraintValidatorClasses = Collections.unmodifiableList( genericValidatorClasses ); + } + else { + List>> validatorClasses = newArrayList(); + validatorClasses.add( crossParameterConstraintValidatorClass ); + this.applyingConstraintValidatorClasses = Collections.unmodifiableList( validatorClasses ); + } } public ConstraintDescriptorImpl(Member member, @@ -223,6 +240,16 @@ public ConstraintTarget getValidationAppliesTo() { return constraintValidatorDefinitionClasses; } + /** + * Returns those validators registered with this constraint which apply to + * the given constraint type (either generic or cross-parameter). + * + * @return The validators applying to type of this constraint. + */ + public List>> getApplyingConstraintValidatorClasses() { + return applyingConstraintValidatorClasses; + } + @Override public Map getAttributes() { return attributes; @@ -445,12 +472,26 @@ private Set> buildGroupSet(Class implicitGroup) { return crossParameterValidatorClass; } + private List>> findGenericValidatorClasses(List>> constraintValidatorDefinitionClasses) { + List>> genericValidatorClasses = newArrayList(); + + for ( Class> validatorClass : constraintValidatorDefinitionClasses ) { + if ( supportsValidationTarget( validatorClass, ValidationTarget.ANNOTATED_ELEMENT ) ) { + genericValidatorClasses.add( validatorClass ); + } + } + + return genericValidatorClasses; + } + private boolean supportsValidationTarget(Class validatorClass, ValidationTarget target) { SupportedValidationTarget supportedTargetAnnotation = validatorClass.getAnnotation( SupportedValidationTarget.class ); + + //by default constraints target the annotated element if ( supportedTargetAnnotation == null ) { - return false; + return target == ValidationTarget.ANNOTATED_ELEMENT; } ValidationTarget[] targets = supportedTargetAnnotation.value(); for ( ValidationTarget configuredTarget : targets ) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/TypeHelper.java b/engine/src/main/java/org/hibernate/validator/internal/util/TypeHelper.java index 7639d3fe8f..a329332c59 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/util/TypeHelper.java +++ b/engine/src/main/java/org/hibernate/validator/internal/util/TypeHelper.java @@ -27,8 +27,6 @@ import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -39,6 +37,9 @@ 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; +import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet; + /** * Provides utility methods for working with types. * @@ -51,7 +52,7 @@ public final class TypeHelper { private static final Log log = LoggerFactory.make(); static { - Map, Set>> subtypesByPrimitive = new HashMap, Set>>(); + Map, Set>> subtypesByPrimitive = newHashMap(); putPrimitiveSubtypes( subtypesByPrimitive, Void.TYPE ); putPrimitiveSubtypes( subtypesByPrimitive, Boolean.TYPE ); @@ -219,6 +220,7 @@ public static Type getArrayType(Type componentType) { public static GenericArrayType genericArrayType(final Type componentType) { return new GenericArrayType() { + @Override public Type getGenericComponentType() { return componentType; } @@ -241,14 +243,17 @@ public static boolean isInstance(Type type, Object object) { */ public static ParameterizedType parameterizedType(final Class rawType, final Type... actualTypeArguments) { return new ParameterizedType() { + @Override public Type[] getActualTypeArguments() { return actualTypeArguments; } + @Override public Type getRawType() { return rawType; } + @Override public Type getOwnerType() { return null; } @@ -291,7 +296,7 @@ public static Type[] getResolvedInterfaces(Type type) { public static Map>> getValidatorsTypes( List>> validators) { Map>> validatorsTypes = - new HashMap>>(); + newHashMap(); for ( Class> validator : validators ) { validatorsTypes.put( extractType( validator ), validator ); } @@ -300,7 +305,7 @@ public static Type[] getResolvedInterfaces(Type type) { } private static Type extractType(Class> validator) { - Map resolvedTypes = new HashMap(); + Map resolvedTypes = newHashMap(); Type constraintValidatorType = resolveTypes( resolvedTypes, validator ); //we now have all bind from a type to its resolution at one level @@ -375,7 +380,7 @@ private static Type resolveTypeForClassAndHierarchy(Map resolvedType private static void putPrimitiveSubtypes(Map, Set>> subtypesByPrimitive, Class primitiveType, Class... directSubtypes) { - Set> subtypes = new HashSet>(); + Set> subtypes = newHashSet(); for ( Class directSubtype : directSubtypes ) { subtypes.add( directSubtype ); diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/constraintvalidation/ConstraintValidatorManagerTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/constraintvalidation/ConstraintValidatorManagerTest.java index 209e193f95..a2c99b5d85 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/constraintvalidation/ConstraintValidatorManagerTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/constraintvalidation/ConstraintValidatorManagerTest.java @@ -33,6 +33,7 @@ import org.hibernate.validator.internal.constraintvalidators.NotNullValidator; import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorFactoryImpl; import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager; +import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl; import org.hibernate.validator.testutil.TestForIssue; import static org.fest.assertions.Assertions.assertThat; @@ -68,7 +69,7 @@ public void testGetDefaultConstraintValidatorFactory() { @Test public void testGetInitializedValidator() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); ConstraintValidator constraintValidator = constraintValidatorManager.getInitializedValidator( String.class, @@ -81,7 +82,7 @@ public void testGetInitializedValidator() { @Test(expectedExceptions = IllegalArgumentException.class) public void testNullValidatedValueThrowsIllegalArgumentException() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); constraintValidatorManager.getInitializedValidator( null, @@ -102,7 +103,7 @@ public void testNullDescriptorThrowsIllegalArgumentException() { @Test(expectedExceptions = IllegalArgumentException.class) public void testNullFactoryThrowsIllegalArgumentException() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); constraintValidatorManager.getInitializedValidator( String.class, @@ -114,7 +115,7 @@ public void testNullFactoryThrowsIllegalArgumentException() { @Test(expectedExceptions = UnexpectedTypeException.class, expectedExceptionsMessageRegExp = "HV000030.*") public void testUnexpectedTypeException() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s2" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s2" ); constraintValidatorManager.getInitializedValidator( Object.class, @@ -125,7 +126,7 @@ public void testUnexpectedTypeException() { @Test public void testConstraintValidatorInstancesAreCachedPerFactory() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); ConstraintValidator constraintValidator1 = constraintValidatorManager.getInitializedValidator( String.class, @@ -158,7 +159,7 @@ public void testConstraintValidatorInstancesAreCachedPerFactory() { @Test public void testOnlyTheInstancesForTheLeastRecentlyUsedCustomFactoryAreCached() { - ConstraintDescriptor constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); + ConstraintDescriptorImpl constraintDescriptor = getConstraintDescriptorForProperty( "s1" ); for ( int i = 0; i < 10; i++ ) { constraintValidatorManager.getInitializedValidator( @@ -193,10 +194,10 @@ public void testValidatorsAreCachedPerConstraint() { .buildValidatorFactory() .getValidator(); - ConstraintDescriptor notNullOnFirstNameDescriptor = getSingleConstraintDescriptorForProperty( + ConstraintDescriptorImpl notNullOnFirstNameDescriptor = getSingleConstraintDescriptorForProperty( validator, User.class, "firstName" ); - ConstraintDescriptor notNullOnLastNameDescriptor = getSingleConstraintDescriptorForProperty( + ConstraintDescriptorImpl notNullOnLastNameDescriptor = getSingleConstraintDescriptorForProperty( validator, User.class, "lastName" ); @@ -226,13 +227,13 @@ public void testValidatorsAreCachedPerConstraintAndAnnotationMembers() { .buildValidatorFactory() .getValidator(); - ConstraintDescriptor sizeOnMiddleNameDescriptor = getSingleConstraintDescriptorForProperty( + ConstraintDescriptorImpl sizeOnMiddleNameDescriptor = getSingleConstraintDescriptorForProperty( validator, User.class, "middleName" ); - ConstraintDescriptor sizeOnAddress1Descriptor = getSingleConstraintDescriptorForProperty( + ConstraintDescriptorImpl sizeOnAddress1Descriptor = getSingleConstraintDescriptorForProperty( validator, User.class, "address1" ); - ConstraintDescriptor sizeOnAddress2Descriptor = getSingleConstraintDescriptorForProperty( + ConstraintDescriptorImpl sizeOnAddress2Descriptor = getSingleConstraintDescriptorForProperty( validator, User.class, "address2" ); @@ -250,11 +251,11 @@ public void testValidatorsAreCachedPerConstraintAndAnnotationMembers() { assertThat( sizeValidatorForAddress1 ).isSameAs( sizeValidatorForAddress2 ); } - private ConstraintDescriptor getConstraintDescriptorForProperty(String propertyName) { + private ConstraintDescriptorImpl getConstraintDescriptorForProperty(String propertyName) { return getSingleConstraintDescriptorForProperty( validator, Foo.class, propertyName ); } - private ConstraintDescriptor getSingleConstraintDescriptorForProperty(Validator validator, Class clazz, String propertyName) { + private ConstraintDescriptorImpl getSingleConstraintDescriptorForProperty(Validator validator, Class clazz, String propertyName) { BeanDescriptor beanDescriptor = validator.getConstraintsForClass( clazz ); PropertyDescriptor propertyDescriptor = beanDescriptor.getConstraintsForProperty( propertyName @@ -265,7 +266,7 @@ private ConstraintDescriptor getSingleConstraintDescriptorForProperty(Validat 1, "There should be only one constraint descriptor" ); - return constraintDescriptorSet.iterator().next(); + return (ConstraintDescriptorImpl) constraintDescriptorSet.iterator().next(); } public class Foo { @@ -290,6 +291,7 @@ public MyCustomValidatorFactory() { @Override public void releaseInstance(ConstraintValidator instance) { - delegate.releaseInstance( instance ); } + delegate.releaseInstance( instance ); + } } }