Handle composite constraints.
[JSR 303 TCK Result] 36 of 258 (13.95%) Pass with 15 Failures and 16 Errors.

Review at http://gwt-code-reviews.appspot.com/1231801

Review by: rchandia@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9463 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/validation/src/com/google/gwt/sample/validation/shared/Address.java b/samples/validation/src/com/google/gwt/sample/validation/shared/Address.java
index f2702d6..f340eab 100644
--- a/samples/validation/src/com/google/gwt/sample/validation/shared/Address.java
+++ b/samples/validation/src/com/google/gwt/sample/validation/shared/Address.java
@@ -27,4 +27,8 @@
   @NotNull
   public String street;
 
+  @Zip
+  public String zip;
+
+
 }
diff --git a/samples/validation/src/com/google/gwt/sample/validation/shared/Zip.java b/samples/validation/src/com/google/gwt/sample/validation/shared/Zip.java
new file mode 100644
index 0000000..ffc8ec3
--- /dev/null
+++ b/samples/validation/src/com/google/gwt/sample/validation/shared/Zip.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validation.shared;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * Example composite constraint.
+ */
+@Pattern(regexp = "[0-9]*")
+@Size(min = 5, max = 5)
+@Constraint(validatedBy = {})
+@Documented
+@Target({ANNOTATION_TYPE, METHOD, FIELD, CONSTRUCTOR, PARAMETER})
+@Retention(RUNTIME)
+public @interface Zip {
+  /**
+   * Defines several @Zip annotations on the same element
+   *
+   * @see {@link Zip}
+   */
+  @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
+  @Retention(RUNTIME)
+  @Documented
+  @interface List {
+    Zip[] value();
+  }
+
+  Class<?>[] groups() default {};
+
+  String message() default "Wrong zipcode";
+
+  Class<? extends Payload>[] payload() default {};
+}
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionGwtSuite.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionGwtSuite.java
new file mode 100644
index 0000000..ed6a4ab
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionGwtSuite.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.constraints.constraintcomposition;
+
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * Tck Tests for the {@code constraints composition} package.
+ */
+public class ConstraintCompositionGwtSuite {
+  public static Test suite() {
+    GWTTestSuite suite = new GWTTestSuite(
+        "TCK for GWT Validation, constraints composition package");
+    suite.addTestSuite(ConstraintCompositionTest.class);
+    return suite;
+  }
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionTest.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionTest.java
new file mode 100644
index 0000000..98e7ada
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/ConstraintCompositionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.constraints.constraintcomposition;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Wraps
+ * {@link org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.ConstraintCompositionTest}
+ * .
+ */
+public class ConstraintCompositionTest extends GWTTestCase {
+  private final org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.ConstraintCompositionTest delegate =
+      new  org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.ConstraintCompositionTest();
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.sample.validationtck.constraints.constraintcomposition.TckTest";
+  }
+
+  public void testAllComposingConstraintsMustBeApplicableToAnnotatedType() {
+    delegate.testAllComposingConstraintsMustBeApplicableToAnnotatedType();
+  }
+
+  public void testAttributesDefinedOnComposingConstraints() {
+    delegate.testAttributesDefinedOnComposingConstraints();
+  }
+
+  public void testComposedConstraints() {
+    delegate.testComposedConstraints();
+  }
+
+  public void testComposedConstraintsAreRecursive() {
+    delegate.testComposedConstraintsAreRecursive();
+  }
+
+  public void testEachFailingConstraintCreatesConstraintViolation() {
+    delegate.testEachFailingConstraintCreatesConstraintViolation();
+  }
+
+  public void testGroupsDefinedOnMainAnnotationAreInherited() {
+    delegate.testGroupsDefinedOnMainAnnotationAreInherited();
+  }
+
+  public void testOnlySingleConstraintViolation() {
+    delegate.testOnlySingleConstraintViolation();
+  }
+
+  public void testOverriddenAttributesMustMatchInType() {
+    delegate.testOverriddenAttributesMustMatchInType();
+  }
+
+  public void testPayloadPropagationInComposedConstraints() {
+    delegate.testPayloadPropagationInComposedConstraints();
+  }
+
+  public void testValidationOfMainAnnotationIsAlsoApplied() {
+    delegate.testValidationOfMainAnnotationIsAlsoApplied();
+  }
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml
new file mode 100644
index 0000000..a2b50cc
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.1/distro-source/core/src/gwt-module.dtd">
+<!--
+  Copyright 2010 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License. You may obtain a copy of
+  the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+  License for the specific language governing permissions and limitations under
+  the License.
+-->
+<module>
+  <inherits name="com.google.gwt.sample.validationtck.ValidationTck" />
+  <source path="">
+    <include name="*.java" />
+    <exclude name="super" />
+  </source>
+  <replace-with class="com.google.gwt.sample.validationtck.constraints.constraintcomposition.TckTestValidator">
+    <when-type-is class="javax.validation.Validator"/>
+  </replace-with>
+</module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java
new file mode 100644
index 0000000..76c1531
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.constraints.constraintcomposition;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.AbstractValidator;
+import com.google.gwt.validation.client.GwtValidation;
+
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.Address;
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.FrenchAddress;
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.Friend;
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.GermanAddress;
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.Shoe;
+
+import javax.validation.Validator;
+
+/**
+ * {@link Validator} implementation that uses
+ * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
+ */
+public final class TckTestValidator extends AbstractValidator {
+  /**
+   * Marker Interface for {@link GWT#create(Class)}.
+   */
+  @GwtValidation(value = {
+      Address.class, FrenchAddress.class, Friend.class, GermanAddress.class,
+      Shoe.class
+  // TODO(nchalko) handle ConstraintDefinitionException
+  // ConstraintCompositionTest.DummyEntityWithZipCode.class
+  })
+  public static interface GwtValidator extends Validator {
+  }
+
+  public TckTestValidator() {
+    super((Validator) GWT.create(GwtValidator.class));
+  }
+}
diff --git a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
index a7efab0..4d5e720 100644
--- a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.UnsafeNativeLong;
+import com.google.gwt.core.ext.Generator;
 import com.google.gwt.core.ext.GeneratorContext;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.TreeLogger.Type;
@@ -117,7 +118,7 @@
       return jProgram.getLiteralLong(((Long) value).intValue()).toSource();
     }
     if (value instanceof String) {
-      return '"' + ((String) value).toString().replace("\"", "\\\"") + '"';
+      return '"' + Generator.escape((String) value) + '"';
     }
     // TODO(nchalko) handle the rest of the literal types
     throw new IllegalArgumentException(value.getClass()
@@ -726,6 +727,37 @@
     sw.println("}");
   }
 
+  private void writeValidateConstraint(SourceWriter sw, PropertyDescriptor p,
+      Class<?> elementClass, ConstraintDescriptor<?> constraint,
+      String constraintDescriptorVar) {
+    Class<? extends ConstraintValidator<? extends Annotation, ?>> validatorClass = 
+        getValidatorForType(constraint, elementClass);
+    if (validatorClass == null) {
+      // TODO(nchalko) What does the spec say to do here.
+      logger.log(Type.WARN, "No ConstraintValidator of " + constraint + " for "
+          + p.getPropertyName() + " of type " + elementClass);
+
+    } else {
+      // TODO(nchalko) handle constraint.isReportAsSingleViolation()
+      // validate(context, violations, object, value, new MyValidator(),
+      // constraintDescriptor, groups);
+      sw.print("validate(context, violations, object, value, ");
+      sw.print("new "); // new one each time because validators are not
+                        // thread safe
+                        // TODO(nchalko) use ConstraintValidatorFactory
+      sw.print(validatorClass.getCanonicalName());
+      sw.print("(), ");
+      sw.print(constraintDescriptorVar);
+      sw.println(", groups);");
+    }
+    int count = 0;
+    for (ConstraintDescriptor<?> compositeConstraint : constraint.getComposingConstraints()) {
+      String compositeVar = constraintDescriptorVar + "_" + count++;
+      writeValidateConstraint(sw, p, elementClass, compositeConstraint,
+          compositeVar);
+    }
+  }
+
   private void writeValidateFieldCall(SourceWriter sw, PropertyDescriptor p,
       boolean useValue) {
     String propertyName = p.getPropertyName();
@@ -933,27 +965,11 @@
       if (annotation != null) {
         // TODO(nchalko) check for annotation equality
 
-        Class<? extends ConstraintValidator<? extends Annotation, ?>> validatorClass = getValidatorForType(
-            constraint, elementClass);
-        if (validatorClass == null) {
-          // TODO(nchalko) What does the spec say to do here.
-          logger.log(Type.WARN, "No ConstraintValidator of " + constraint
-              + " for " + p.getPropertyName() + " of type " + elementClass);
+        String constraintDescriptorVar = constraintDescriptorVar(
+            p.getPropertyName(), count);
 
-        } else {
-          // TODO(nchalko) handle constraint.isReportAsSingleViolation() and
-          // hasComposingConstraints
-
-          // validate(context, violations, object, value, new MyValidator(),
-          // constraintDescriptor, groups);
-          sw.print("validate(context, violations, object, value, ");
-          sw.print("new "); // new one each time because validators are not
-                            // thread safe
-          sw.print(validatorClass.getCanonicalName());
-          sw.print("(), ");
-          sw.print(constraintDescriptorVar(p.getPropertyName(), count));
-          sw.println(", groups);");
-        }
+        writeValidateConstraint(sw, p, elementClass, constraint,
+            constraintDescriptorVar);
       }
       count++; // index starts at zero
     }