[hibernate-commits] Hibernate SVN: r16505 - in validator/trunk/hibernate-validator/src: test/java/org/hibernate/validation/engine/resolver and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon May 4 08:42:25 EDT 2009


Author: epbernard
Date: 2009-05-04 08:42:25 -0400 (Mon, 04 May 2009)
New Revision: 16505

Added:
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/SnifferTraversableResolver.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/TraversableResolverTest.java
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/ValidatorImpl.java
Log:
HV-157 cascading no longer executed if isTraversable returns false

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-05-03 21:41:37 UTC (rev 16504)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ExecutionContext.java	2009-05-04 12:42:25 UTC (rev 16505)
@@ -25,6 +25,9 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.Stack;
+import java.lang.reflect.Member;
+import java.lang.reflect.Field;
+import java.lang.annotation.ElementType;
 import javax.validation.ConstraintDescriptor;
 import javax.validation.ConstraintValidatorFactory;
 import javax.validation.ConstraintViolation;
@@ -293,8 +296,18 @@
 				peekParentPath(),
 				metaConstraint.getElementType()
 		);
-	}  
+	}
 
+	public boolean isCascadeRequired(Member member) {
+		return traversableResolver.isTraversable(
+				peekCurrentBean(),
+				peekProperty(),
+				getRootBeanClass(),
+				peekParentPath(),
+				member instanceof Field ? ElementType.FIELD : ElementType.METHOD
+		);
+	}
+
 	public List<ConstraintViolationImpl<T>> createConstraintViolations(Object value, ConstraintValidatorContextImpl constraintValidatorContext) {
 		List<ConstraintViolationImpl<T>> constraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
 		for ( ConstraintValidatorContextImpl.ErrorMessage error : constraintValidatorContext.getErrorMessages() ) {

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-05-03 21:41:37 UTC (rev 16504)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java	2009-05-04 12:42:25 UTC (rev 16505)
@@ -279,10 +279,12 @@
 		for ( Member member : cascadedMembers ) {
 			Type type = ReflectionHelper.typeOf( member );
 			context.pushProperty( ReflectionHelper.getPropertyName( member ) );
-			Object value = ReflectionHelper.getValue( member, context.peekCurrentBean() );
-			if ( value != null ) {
-				Iterator<?> iter = createIteratorForCascadedValue( context, type, value );
-				validateCascadedConstraint( context, iter );
+			if ( context.isCascadeRequired( member ) ) {
+				Object value = ReflectionHelper.getValue( member, context.peekCurrentBean() );
+				if ( value != null ) {
+					Iterator<?> iter = createIteratorForCascadedValue( context, type, value );
+					validateCascadedConstraint( context, iter );
+				}
 			}
 			context.popProperty();
 		}

Added: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/SnifferTraversableResolver.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/SnifferTraversableResolver.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/SnifferTraversableResolver.java	2009-05-04 12:42:25 UTC (rev 16505)
@@ -0,0 +1,108 @@
+package org.hibernate.validation.engine.resolver;
+
+import java.lang.annotation.ElementType;
+import java.util.Set;
+import java.util.HashSet;
+import javax.validation.TraversableResolver;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SnifferTraversableResolver implements TraversableResolver {
+	Set<String> paths = new HashSet<String>();
+	Set<Call> calls = new HashSet<Call>();
+
+	public SnifferTraversableResolver(Suit suit) {
+		calls.add( new Call(suit, "size", Suit.class, "", ElementType.FIELD ) );
+		calls.add( new Call(suit, "trousers", Suit.class, "", ElementType.FIELD ) );
+		calls.add( new Call(suit.getTrousers(), "length", Suit.class, "trousers", ElementType.FIELD ) );
+		calls.add( new Call(suit, "jacket", Suit.class, "", ElementType.METHOD ) );
+		calls.add( new Call(suit.getJacket(), "width", Suit.class, "jacket", ElementType.METHOD ) );
+	}
+
+	public Set<String> getPaths() {
+		return paths;
+	}
+
+	//TODO add test with correct paths and types to make sure the impl does not mess it up
+	public boolean isTraversable(Object traversableObject, String traversableProperty, Class<?> rootBeanType, String pathToTraversableObject, ElementType elementType) {
+		String path = "";
+		if (! (pathToTraversableObject == null || pathToTraversableObject.length() == 0 ) ) {
+			path = pathToTraversableObject + ".";
+		}
+		paths.add( path + traversableProperty );
+		Call call = new Call(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType);
+		if ( ! calls.contains( call ) ) {
+
+			throw new IllegalStateException( "Unexpected " + call.toString() );
+		}
+		return true;
+	}
+
+	private static final class Call {
+		private Object traversableObject;
+		private String traversableProperty;
+		private Class<?> rootBeanType;
+		private String pathToTraversableObject;
+		private ElementType elementType;
+
+		private Call(Object traversableObject, String traversableProperty, Class<?> rootBeanType, String pathToTraversableObject, ElementType elementType) {
+			this.traversableObject = traversableObject;
+			this.traversableProperty = traversableProperty;
+			this.rootBeanType = rootBeanType;
+			this.pathToTraversableObject = pathToTraversableObject;
+			this.elementType = elementType;
+		}
+
+		@Override
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( o == null || getClass() != o.getClass() ) {
+				return false;
+			}
+
+			Call call = ( Call ) o;
+
+			if ( elementType != call.elementType ) {
+				return false;
+			}
+			if ( !pathToTraversableObject.equals( call.pathToTraversableObject ) ) {
+				return false;
+			}
+			if ( !rootBeanType.equals( call.rootBeanType ) ) {
+				return false;
+			}
+			if ( traversableObject != null ? !(traversableObject == call.traversableObject) : call.traversableObject != null ) {
+				return false;
+			}
+			if ( !traversableProperty.equals( call.traversableProperty ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		@Override
+		public int hashCode() {
+			int result = traversableObject != null ? traversableObject.hashCode() : 0;
+			result = 31 * result + traversableProperty.hashCode();
+			result = 31 * result + rootBeanType.hashCode();
+			result = 31 * result + pathToTraversableObject.hashCode();
+			result = 31 * result + elementType.hashCode();
+			return result;
+		}
+
+		@Override
+		public String toString() {
+			return "Call{" +
+					"traversableObject=" + traversableObject +
+					", traversableProperty='" + traversableProperty + '\'' +
+					", rootBeanType=" + rootBeanType +
+					", pathToTraversableObject='" + pathToTraversableObject + '\'' +
+					", elementType=" + elementType +
+					'}';
+		}
+	}
+}

Copied: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/TraversableResolverTest.java (from rev 16497, validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/CachedTraversableResolverTest.java)
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/TraversableResolverTest.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/resolver/TraversableResolverTest.java	2009-05-04 12:42:25 UTC (rev 16505)
@@ -0,0 +1,41 @@
+package org.hibernate.validation.engine.resolver;
+
+import java.lang.annotation.ElementType;
+import java.util.HashSet;
+import java.util.Set;
+import javax.validation.TraversableResolver;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+import javax.validation.Validator;
+import javax.validation.groups.Default;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+import org.hibernate.validation.engine.HibernateValidatorConfiguration;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class TraversableResolverTest {
+	@Test
+	public void testCorrectPathsAreRequested() {
+		Suit suit = new Suit();
+				suit.setTrousers( new Trousers() );
+				suit.setJacket( new Jacket() );
+				suit.setSize( 3333 );
+				suit.getTrousers().setLength( 32321 );
+				suit.getJacket().setWidth( 432432 );
+
+		SnifferTraversableResolver resolver = new SnifferTraversableResolver(suit);
+		ValidatorFactory factory = Validation.byDefaultProvider()
+				.configure().traversableResolver( resolver )
+				.buildValidatorFactory();
+		Validator v = factory.getValidator();
+
+		//Raises an IllegalStateException if something goes wrong
+		v.validate( suit, Default.class, Cloth.class );
+
+		assertEquals( 5, resolver.getPaths().size() );
+	}
+}
\ No newline at end of file




More information about the hibernate-commits mailing list