[hibernate-commits] Hibernate SVN: r16179 - in validator/trunk/hibernate-validator: src/main/java/org/hibernate/validation/engine and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Mar 18 07:08:10 EDT 2009


Author: hardy.ferentschik
Date: 2009-03-18 07:08:10 -0400 (Wed, 18 Mar 2009)
New Revision: 16179

Modified:
   validator/trunk/hibernate-validator/pom.xml
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/util/IdentitySet.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/graphnavigation/GraphNavigationTest.java
   validator/trunk/hibernate-validator/src/test/resources/log4j.properties
Log:
HV-126 added support for one validation per group AND path

Modified: validator/trunk/hibernate-validator/pom.xml
===================================================================
--- validator/trunk/hibernate-validator/pom.xml	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/pom.xml	2009-03-18 11:08:10 UTC (rev 16179)
@@ -22,7 +22,7 @@
         <dependency>
             <groupId>javax.validation</groupId>
             <artifactId>validation-api</artifactId>
-            <version>1.0.CR1-SNAPSHOT</version>
+            <version>1.0.CR1</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java	2009-03-18 11:08:10 UTC (rev 16179)
@@ -19,8 +19,11 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Stack;
 import javax.validation.ConstraintDescriptor;
 import javax.validation.ConstraintValidatorContext;
@@ -51,12 +54,17 @@
 	private final T rootBean;
 
 	/**
-	 * Maps for each group to an identity set to keep track of already validated objects. We have to make sure
-	 * that each object gets only validated once (per group).
+	 * Maps a group to an identity set to keep track of already validated objects. We have to make sure
+	 * that each object gets only validated once per group and property path.
 	 */
 	private final Map<Class<?>, IdentitySet> processedObjects;
 
 	/**
+	 * Maps an object to a list of paths in which it has been invalidated.
+	 */
+	private final Map<Object, Set<String>> processedPaths;
+
+	/**
 	 * A list of all failing constraints so far.
 	 */
 	private final List<ConstraintViolationImpl<T>> failingConstraintViolations;
@@ -83,6 +91,13 @@
 	private Stack<Object> beanStack = new Stack<Object>();
 
 	/**
+	 * Flag indicating whether an object can only be validated once per group or once per group AND validation path.
+	 *
+	 * @todo Make this boolean a configurable item.
+	 */
+	private boolean allowOneValidationPerPath = true;
+
+	/**
 	 * The message resolver which should be used in this context.
 	 */
 	private final MessageInterpolator messageInterpolator;
@@ -109,6 +124,7 @@
 
 		beanStack.push( object );
 		processedObjects = new HashMap<Class<?>, IdentitySet>();
+		processedPaths = new IdentityHashMap<Object, Set<String>>();
 		propertyPath = new ArrayList<String>();
 		failingConstraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
 	}
@@ -168,31 +184,42 @@
 
 	public void setCurrentGroup(Class<?> currentGroup) {
 		this.currentGroup = currentGroup;
+		markProcessed();
 	}
 
-	public void markProcessedForCurrentGroup() {
-		if ( processedObjects.containsKey( currentGroup ) ) {
-			processedObjects.get( currentGroup ).add( beanStack.peek() );
+	/**
+	 * Returns <code>true</code> if the specified value has already been validated, <code>false</code> otherwise.
+	 * Each object can only be validated once per group and validation path. The flag {@link #allowOneValidationPerPath}
+	 * determines whether an object can only be validated once per group or once per group and validation path.Ê
+	 *
+	 * @param value The value to be validated.
+	 *
+	 * @return Returns <code>true</code> if the specified value has already been validated, <code>false</code> otherwise.
+	 */
+	public boolean isAlreadyValidated(Object value) {
+		boolean alreadyValidated;
+		alreadyValidated = isAlreadyValidatedForCurrentGroup( value );
+
+		if ( alreadyValidated && allowOneValidationPerPath ) {
+			alreadyValidated = isAlreadyValidatedForPath( value );
 		}
-		else {
-			IdentitySet set = new IdentitySet();
-			set.add( beanStack.peek() );
-			processedObjects.put( currentGroup, set );
+		return alreadyValidated;
+	}
+
+	private boolean isAlreadyValidatedForPath(Object value) {
+		for ( String path : processedPaths.get( value ) ) {
+			if ( path.contains( peekPropertyPath() ) || peekPropertyPath().contains( path ) ) {
+				return true;
+			}
 		}
+		return false;
 	}
 
-	public boolean isValidatedAgainstCurrentGroup(Object value) {
+	private boolean isAlreadyValidatedForCurrentGroup(Object value) {
 		final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( currentGroup );
 		return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
 	}
 
-	private void addConstraintFailure(ConstraintViolationImpl<T> failingConstraintViolation) {
-		int i = failingConstraintViolations.indexOf( failingConstraintViolation );
-		if ( i == -1 ) {
-			failingConstraintViolations.add( failingConstraintViolation );
-		}
-	}
-
 	public void addConstraintFailures(List<ConstraintViolationImpl<T>> failingConstraintViolations) {
 		for ( ConstraintViolationImpl<T> violation : failingConstraintViolations ) {
 			addConstraintFailure( violation );
@@ -226,15 +253,16 @@
 	public void markCurrentPropertyAsIndexed() {
 		String property = peekProperty();
 		property += "[]";
-		popProperty();
+		propertyPath.remove( propertyPath.size() - 1 );
 		pushProperty( property );
 	}
 
-	public void replacePropertyIndex(String index) {
+	public void setPropertyIndex(String index) {
+		String property = peekProperty();
+
 		// replace the last occurance of [<oldIndex>] with [<index>]
-		String property = peekProperty();
 		property = property.replaceAll( "\\[[0-9]*\\]$", "[" + index + "]" );
-		popProperty();
+		propertyPath.remove( propertyPath.size() - 1 );
 		pushProperty( property );
 	}
 
@@ -297,12 +325,48 @@
 		);
 	}
 
+	private void markProcessed() {
+		markProcessForCurrentGroup();
+		if ( allowOneValidationPerPath ) {
+			markProcessedForCurrentPath();
+		}
+	}
+
+	private void markProcessedForCurrentPath() {
+		if ( processedPaths.containsKey( peekCurrentBean() ) ) {
+			processedPaths.get( peekCurrentBean() ).add( peekPropertyPath() );
+		}
+		else {
+			Set<String> set = new HashSet<String>();
+			set.add( peekPropertyPath() );
+			processedPaths.put( peekCurrentBean(), set );
+		}
+	}
+
+	private void markProcessForCurrentGroup() {
+		if ( processedObjects.containsKey( currentGroup ) ) {
+			processedObjects.get( currentGroup ).add( peekCurrentBean() );
+		}
+		else {
+			IdentitySet set = new IdentitySet();
+			set.add( peekCurrentBean() );
+			processedObjects.put( currentGroup, set );
+		}
+	}
+
+	private void addConstraintFailure(ConstraintViolationImpl<T> failingConstraintViolation) {
+		int i = failingConstraintViolations.indexOf( failingConstraintViolation );
+		if ( i == -1 ) {
+			failingConstraintViolations.add( failingConstraintViolation );
+		}
+	}
+
 	class ValidatedProperty {
 
 		private final List<ErrorMessage> errorMessages = new ArrayList<ErrorMessage>( 3 );
 		private final String property;
 		private final String propertyParent;
-		private ConstraintDescriptor constraintDescriptor;
+		private ConstraintDescriptor<?> constraintDescriptor;
 		private boolean defaultDisabled;
 
 
@@ -311,11 +375,11 @@
 			this.propertyParent = propertyParent;
 		}
 
-		public void setConstraintDescriptor(ConstraintDescriptor constraintDescriptor) {
+		public void setConstraintDescriptor(ConstraintDescriptor<?> constraintDescriptor) {
 			this.constraintDescriptor = constraintDescriptor;
 		}
 
-		public ConstraintDescriptor getConstraintDescriptor() {
+		public ConstraintDescriptor<?> getConstraintDescriptor() {
 			return constraintDescriptor;
 		}
 

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/MetaConstraint.java	2009-03-18 11:08:10 UTC (rev 16179)
@@ -21,7 +21,6 @@
 import java.lang.annotation.ElementType;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
@@ -46,11 +45,6 @@
 	private final ConstraintTree<A> constraintTree;
 
 	/**
-	 * The type the constraint was defined on.
-	 */
-	private final Type type;
-
-	/**
 	 * The member the constraint was defined on.
 	 */
 	private final Member member;
@@ -71,12 +65,11 @@
 	 */
 	private final Class<T> beanClass;
 
-	public MetaConstraint(Type type, ConstraintDescriptor<A> constraintDescriptor) {
-		this.type = type;
+	public MetaConstraint(Class<T> beanClass, ConstraintDescriptor<A> constraintDescriptor) {
 		this.elementType = ElementType.TYPE;
 		this.member = null;
 		this.propertyName = "";
-		this.beanClass = ( Class<T> ) type.getClass();
+		this.beanClass = beanClass;
 		constraintTree = new ConstraintTree<A>( constraintDescriptor );
 	}
 
@@ -90,7 +83,6 @@
 		else {
 			throw new IllegalArgumentException( "Non allowed member type: " + member );
 		}
-		this.type = null;
 		this.member = member;
 		this.propertyName = ReflectionHelper.getPropertyName( member );
 		this.beanClass = beanClass;
@@ -170,7 +162,7 @@
 		Type t;
 		switch ( elementType ) {
 			case TYPE: {
-				t = type;
+				t = beanClass;
 				break;
 			}
 			default: {

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java	2009-03-18 11:08:10 UTC (rev 16179)
@@ -201,7 +201,7 @@
 			validateCascadedConstraints( context );
 		}
 
-		// process sequences depth-first to guarantee that groups following a violation within a group won't get executed. 
+		// process group sequences depth-first to guarantee that groups following a violation within a group won't get executed.
 		Iterator<List<Group>> sequenceIterator = groupChain.getSequenceIterator();
 		while ( sequenceIterator.hasNext() ) {
 			List<Group> sequence = sequenceIterator.next();
@@ -270,7 +270,6 @@
 			}
 			executionContext.popProperty();
 		}
-		executionContext.markProcessedForCurrentGroup();
 		return validationSuccessful;
 	}
 
@@ -339,14 +338,11 @@
 				actualValue = ( ( Map.Entry ) actualValue ).getValue();
 			}
 
-			if ( !context.isValidatedAgainstCurrentGroup( actualValue ) ) {
-				context.replacePropertyIndex( propertyIndex );
-
+			if ( !context.isAlreadyValidated( actualValue ) ) {
+				context.setPropertyIndex( propertyIndex );
 				context.pushCurrentBean( actualValue );
-				validateInContext(
-						context,
-						groupChainGenerator.getGroupChainFor( Arrays.asList( new Class<?>[] { context.getCurrentGroup() } ) )
-				);
+				GroupChain groupChain = groupChainGenerator.getGroupChainFor( Arrays.asList( new Class<?>[] { context.getCurrentGroup() } ) );
+				validateInContext( context, groupChain );
 				context.popCurrentBean();
 			}
 			i++;

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/util/IdentitySet.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/util/IdentitySet.java	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/util/IdentitySet.java	2009-03-18 11:08:10 UTC (rev 16179)
@@ -24,7 +24,7 @@
 import java.util.Set;
 
 /**
- * Set that compares object by identity rather than equality.
+ * Set that compares object by identity rather than equality. Wraps around a <code>IdentityHashMap</code>
  *
  * @author Emmanuel Bernard
  */
@@ -104,4 +104,11 @@
 	public Object[] toArray(Object[] a) {
 		return map.keySet().toArray( a );
 	}
+
+	@Override
+	public String toString() {
+		return "IdentitySet{" +
+				"map=" + map +
+				'}';
+	}
 }

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/graphnavigation/GraphNavigationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/graphnavigation/GraphNavigationTest.java	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/graphnavigation/GraphNavigationTest.java	2009-03-18 11:08:10 UTC (rev 16179)
@@ -1,4 +1,4 @@
-// $Id:$
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
@@ -58,6 +58,6 @@
 		Validator validator = TestUtil.getValidator();
 
 		Set<ConstraintViolation<Order>> constraintViolations = validator.validate( order );
-		assertEquals( "Wrong number of constraints", 1, constraintViolations.size() );
+		assertEquals( "Wrong number of constraints", 3, constraintViolations.size() );
 	}
 }

Modified: validator/trunk/hibernate-validator/src/test/resources/log4j.properties
===================================================================
--- validator/trunk/hibernate-validator/src/test/resources/log4j.properties	2009-03-18 10:28:42 UTC (rev 16178)
+++ validator/trunk/hibernate-validator/src/test/resources/log4j.properties	2009-03-18 11:08:10 UTC (rev 16179)
@@ -21,6 +21,5 @@
 log4j.rootLogger=debug, stdout
 
 log4j.logger.org.hibernate.validation.engine.ValidatorImpl=trace
-log4j.logger.org.hibernate.validation.engine.ConstraintTree=trace
-org.hibernate.validation.engine.ResourceBundleMessageInterpolator=info
-
+#log4j.logger.org.hibernate.validation.engine.ConstraintTree=trace
+log4j.logger.org.hibernate.validation.engine.ResourceBundleMessageInterpolator=info




More information about the hibernate-commits mailing list