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