To prevent infinite loops, the Bean Validation implementation must ignore
the cascading operation if the associated object instance has already been
validated in the current navigation path (starting from the root object).
[JSR 303 TCK Result] 108 of 257 (42.02%) Pass with 22 Failures and 9 Errors.
Review at http://gwt-code-reviews.appspot.com/1367802
Review by: rchandia@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9792 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java b/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
index 612813f..576c43d 100644
--- a/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
+++ b/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
@@ -16,6 +16,8 @@
package com.google.gwt.validation.client.impl;
import java.lang.annotation.Annotation;
+import java.util.HashSet;
+import java.util.Set;
import javax.validation.MessageInterpolator;
import javax.validation.metadata.BeanDescriptor;
@@ -24,7 +26,11 @@
/**
* Context for a {@link com.google.gwt.validation.client.GwtValidation}.
*
+ * <p>
+ * NOTE: This class is not thread safe.
+ *
* @param <T> the type of the root bean.
+ *
*/
public class GwtValidationContext<T> {
@@ -35,14 +41,36 @@
private final AbstractGwtValidator validator;
/**
- *
+ * The set of validated object.
+ * <p>
+ * This set is shared with and updated by children contexts created by
+ * {@link #append(String)}, {@link #appendIndex(String, int)} and
+ * {@link #appendKey(String, String)}.
*/
+ private final Set<Object> validatedObjects;
+
public GwtValidationContext(T rootBean, BeanDescriptor beanDescriptor,
MessageInterpolator messageInterpolator, AbstractGwtValidator validator) {
+ this(rootBean, beanDescriptor, messageInterpolator, validator,
+ new HashSet<Object>());
+ }
+
+ private GwtValidationContext(T rootBean, BeanDescriptor beanDescriptor,
+ MessageInterpolator messageInterpolator, AbstractGwtValidator validator,
+ Set<Object> validatedObjects) {
this.rootBean = rootBean;
this.beanDescriptor = beanDescriptor;
this.messageInterpolator = messageInterpolator;
this.validator = validator;
+ this.validatedObjects = validatedObjects;
+ }
+
+ public final void addValidatedObject(Object o) {
+ validatedObjects.add(o);
+ }
+
+ public final boolean alreadyValidated(Object o) {
+ return validatedObjects.contains(o);
}
/**
@@ -53,7 +81,7 @@
*/
public GwtValidationContext<T> append(String name) {
GwtValidationContext<T> temp = new GwtValidationContext<T>(rootBean,
- beanDescriptor, messageInterpolator, validator);
+ beanDescriptor, messageInterpolator, validator, validatedObjects);
temp.path = path.append(name);
return temp;
}
@@ -66,7 +94,7 @@
*/
public GwtValidationContext<T> appendIndex(String name, int index) {
GwtValidationContext<T> temp = new GwtValidationContext<T>(rootBean,
- beanDescriptor, messageInterpolator, validator);
+ beanDescriptor, messageInterpolator, validator, validatedObjects);
temp.path = path.appendIndex(name, index);
return temp;
}
@@ -79,7 +107,7 @@
*/
public GwtValidationContext<T> appendKey(String name, String key) {
GwtValidationContext<T> temp = new GwtValidationContext<T>(rootBean,
- beanDescriptor, messageInterpolator, validator);
+ beanDescriptor, messageInterpolator, validator, validatedObjects);
temp.path = path.appendKey(name, key);
return temp;
}
diff --git a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
index 79c2b56..e5f5329 100644
--- a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
@@ -222,7 +222,7 @@
/**
* Gets the best {@link ConstraintValidator}.
- *
+ *
* <p>
* The ConstraintValidator chosen to validate a declared type
* {@code targetType} is the one where the type supported by the
@@ -230,11 +230,11 @@
* no other ConstraintValidator whose supported type is a supertype of
* {@code type} and not a supertype of the chosen ConstraintValidator
* supported type.
- *
+ *
* @param constraint the constraint to find ConstraintValidators for.
* @param targetType The type to find a ConstraintValidator for.
* @return ConstraintValidator
- *
+ *
* @throws UnexpectedTypeException if there is not exactly one maximally
* specific constraint validator for targetType.
*/
@@ -932,6 +932,9 @@
writeNewViolations(sw);
+ // context.addValidatedObject(object);
+ sw.println("context.addValidatedObject(object);");
+
// /// For each group
// TODO(nchalko) handle the sequence in the AbstractValidator
@@ -988,6 +991,7 @@
writeCatchUnexpectedException(sw,
"\"Error validating " + beanHelper.getTypeCanonicalName() + "\"");
+ // }
sw.outdent();
sw.println("}");
}
@@ -1118,11 +1122,11 @@
sw.println("int i = 0;");
// for (Object instance : value) {
- sw.print("for(Object instance : value) {");
+ sw.println("for(Object instance : value) {");
sw.indent();
- // if(instance != null ) {
- sw.println(" if(instance != null ) {");
+ // if(instance != null && !context.alreadyValidated(instance)) {
+ sw.println(" if(instance != null && !context.alreadyValidated(instance)) {");
sw.indent();
// violations.addAll(
@@ -1160,11 +1164,12 @@
// for (Entry<?, Type> entry : value.entrySet()) {
sw.print("for(");
sw.print(Entry.class.getCanonicalName());
- sw.print("<?, ?> entry : value.entrySet()) {");
+ sw.println("<?, ?> entry : value.entrySet()) {");
sw.indent();
- // if(entry.getValue() != null ) {
- sw.println(" if(entry.getValue() != null ) {");
+ // if(entry.getValue() != null &&
+ // !context.alreadyValidated(entry.getValue())) {
+ sw.println(" if(entry.getValue() != null && !context.alreadyValidated(entry.getValue())) {");
sw.indent();
// violations.addAll(
@@ -1363,10 +1368,19 @@
}
} else {
createBeanHelper(elementClass);
+
+ // if (!context.alreadyValidated(value)) {
+ sw.println(" if (!context.alreadyValidated(value)) {");
+ sw.indent();
+
// violations.addAll(myContext.getValidator().validate(context, value,
// groups));
sw.print("violations.addAll(");
sw.println("myContext.getValidator().validate(myContext, value, groups));");
+
+ // }
+ sw.outdent();
+ sw.println("}");
}
// }
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupGwtTest.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupGwtTest.java
index 76aa763..04b78c7 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupGwtTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupGwtTest.java
@@ -42,7 +42,6 @@
delegate.testCyclicGroupSequence();
}
- @Failing(issue = 5801)
public void testGroups() {
delegate.testGroups();
}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/GraphNavigationGwtTest.java b/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/GraphNavigationGwtTest.java
index d275af9..026d08e 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/GraphNavigationGwtTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/GraphNavigationGwtTest.java
@@ -53,9 +53,7 @@
delegate.testGraphNavigationDeterminism();
}
- @Failing(issue = 5946)
public void testNoEndlessLoop() {
- fail("Fail early so othe tests pass");
delegate.testNoEndlessLoop();
}
@@ -63,7 +61,6 @@
delegate.testNullReferencesGetIgnored();
}
- @Failing(issue = 5946)
public void testTypeOfContainedValueIsDeterminedAtRuntime() {
delegate.testTypeOfContainedValueIsDeterminedAtRuntime();
}