Prevent code for constraints which are not in the groups listed in the @GwtValidation annotation from being generated. This greatly simplifies the creation of server-side-only constraints which will not compile using GWT - just put those contratins in a "server side" group and be sure to not list this group in the @GwtValidation annotation of the Validator.

Also noticed and fixed a few validator factories which did not explicitly list all groups of a group sequence in the @GwtValidation "groups" field.

[JSR 303 TCK Result] 191 of 192 (99.48%) Pass with 0 Failures and 0 Errors.

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


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11227 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/validation/rebind/BeanHelperCache.java b/user/src/com/google/gwt/validation/rebind/BeanHelperCache.java
index 13ee849..52780cc 100644
--- a/user/src/com/google/gwt/validation/rebind/BeanHelperCache.java
+++ b/user/src/com/google/gwt/validation/rebind/BeanHelperCache.java
@@ -127,6 +127,8 @@
 
       // now recurse on all Cascaded elements
       for (PropertyDescriptor p : bean.getConstrainedProperties()) {
+        // TODO(idol) only bother creating objects for properties that have constrains in the groups
+        // specified in @GwtValidation, but not others
         if (p.isCascaded()) {
           doCreateHelperForProp(p, helper, logger, context);
         }
diff --git a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
index a719427..5c66d18 100644
--- a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
@@ -66,6 +66,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -343,12 +344,20 @@
 
   private Set<JMethod> gettersToWrap = Sets.newHashSet();
 
+  private final Set<Class<?>> validGroups;
+
+  private final Map<ConstraintDescriptor<?>, Boolean> validConstraintsMap = Maps.newHashMap();
+
   public GwtSpecificValidatorCreator(JClassType validatorType,
       JClassType beanType, BeanHelper beanHelper, TreeLogger logger,
-      GeneratorContext context, BeanHelperCache cache) {
+      GeneratorContext context, BeanHelperCache cache, Class<?>[] validGroupsFromAnnotation) {
     super(context, logger, validatorType, cache);
     this.beanType = beanType;
     this.beanHelper = beanHelper;
+
+    Set<Class<?>> tempValidGroups = Sets.newHashSet(validGroupsFromAnnotation);
+    tempValidGroups.add(Default.class);
+    this.validGroups = Collections.unmodifiableSet(tempValidGroups);
   }
 
   @Override
@@ -402,6 +411,17 @@
     }
   }
 
+  private boolean areConstraintDescriptorGroupsValid(ConstraintDescriptor<?> constraintDescriptor) {
+    if (validConstraintsMap.containsKey(constraintDescriptor)) {
+      return validConstraintsMap.get(constraintDescriptor);
+    } else {
+      boolean areValid = checkGroups(constraintDescriptor.getGroups());
+      // cache result
+      validConstraintsMap.put(constraintDescriptor, areValid);
+      return areValid;
+    }
+  }
+
   private <T> T[] asArray(Collection<?> collection, T[] array) {
     if (collection == null) {
       return null;
@@ -409,6 +429,15 @@
     return collection.toArray(array);
   }
 
+  private boolean checkGroups(Set<Class<?>> groups) {
+    for (Class<?> group : groups) {
+      if (validGroups.contains(group)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   private String constraintDescriptorVar(String name, int count) {
     String s = name + "_c" + count;
     return s;
@@ -599,9 +628,13 @@
     // .setConstrained(true)
     sw.println(".setConstrained(" + beanDescriptor.isBeanConstrained() + ")");
 
-    for (int count = 0; count < beanDescriptor.getConstraintDescriptors().size(); count++) {
-      // .add(c0)
-      sw.println(".add(" + constraintDescriptorVar("this", count) + ")");
+    int count = 0;
+    for (ConstraintDescriptor<?> constraint : beanDescriptor.getConstraintDescriptors()) {
+      if (areConstraintDescriptorGroupsValid(constraint)) {
+        // .add(c0)
+        sw.println(".add(" + constraintDescriptorVar("this", count) + ")");
+        count++;
+      }
     }
 
     // .put("myProperty", myProperty_pd)
@@ -677,34 +710,36 @@
     int count = 0;
     Class<?> clazz = beanHelper.getClazz();
     for (ConstraintDescriptor<?> constraint : beanHelper.getBeanDescriptor().getConstraintDescriptors()) {
-      if (hasMatchingAnnotation(constraint)) {
+      if (areConstraintDescriptorGroupsValid(constraint)) {
+        if (hasMatchingAnnotation(constraint)) {
 
-        if (!constraint.getConstraintValidatorClasses().isEmpty()) {
-          Class<? extends ConstraintValidator<? extends Annotation, ?>> validatorClass = getValidatorForType(
-              constraint, clazz);
-
-          // validate(context, violations, null, object,
-          sw.print("validate(context, violations, null, object, ");
-
-          // new MyValidtor(),
-          sw.print("new ");
-          sw.print(validatorClass.getCanonicalName());
-          sw.print("(), "); // TODO(nchalko) use ConstraintValidatorFactory
-
-          // this.aConstraintDescriptor, groups);
-          sw.print(constraintDescriptorVar("this", count));
-          sw.print(", ");
-          sw.print(groupsVarName);
-          sw.println(");");
-        } else if (constraint.getComposingConstraints().isEmpty()) {
-          // TODO(nchalko) What does the spec say to do here.
-          logger.log(TreeLogger.WARN, "No ConstraintValidator of " + constraint
-              + " for type " + clazz);
+          if (!constraint.getConstraintValidatorClasses().isEmpty()) {
+            Class<? extends ConstraintValidator<? extends Annotation, ?>> validatorClass =
+                getValidatorForType(constraint, clazz);
+  
+            // validate(context, violations, null, object,
+            sw.print("validate(context, violations, null, object, ");
+  
+            // new MyValidtor(),
+            sw.print("new ");
+            sw.print(validatorClass.getCanonicalName());
+            sw.print("(), "); // TODO(nchalko) use ConstraintValidatorFactory
+  
+            // this.aConstraintDescriptor, groups);
+            sw.print(constraintDescriptorVar("this", count));
+            sw.print(", ");
+            sw.print(groupsVarName);
+            sw.println(");");
+          } else if (constraint.getComposingConstraints().isEmpty()) {
+            // TODO(nchalko) What does the spec say to do here.
+            logger.log(TreeLogger.WARN, "No ConstraintValidator of " + constraint
+                + " for type " + clazz);
+          }
+          // TODO(nchalko) handle constraint.isReportAsSingleViolation() and
+          // hasComposingConstraints
         }
-        // TODO(nchalko) handle constraint.isReportAsSingleViolation() and
-        // hasComposingConstraints
+        count++;
       }
-      count++;
     }
   }
 
@@ -1044,9 +1079,11 @@
       for (ConstraintDescriptor<?> constraint : p.getConstraintDescriptors()) {
         org.hibernate.validator.metadata.ConstraintDescriptorImpl<?> constraintHibernate = 
             (org.hibernate.validator.metadata.ConstraintDescriptorImpl<?>) constraint;
-        writeConstraintDescriptor(sw, constraint, constraintHibernate.getElementType(),
-            convertConstraintOriginEnum(constraintHibernate.getDefinedOn()),
-            constraintDescriptorVar(p.getPropertyName(), count++));
+        if (areConstraintDescriptorGroupsValid(constraint)) {
+          writeConstraintDescriptor(sw, constraint, constraintHibernate.getElementType(),
+              convertConstraintOriginEnum(constraintHibernate.getDefinedOn()),
+              constraintDescriptorVar(p.getPropertyName(), count++));
+        }
       }
       writePropertyDescriptor(sw, p);
       if (p.isCascaded()) {
@@ -1062,9 +1099,11 @@
         beanHelper.getBeanDescriptor().getConstraintDescriptors()) {
       org.hibernate.validator.metadata.ConstraintDescriptorImpl<?> constraintHibernate =
           (org.hibernate.validator.metadata.ConstraintDescriptorImpl<?>) constraint;
-      writeConstraintDescriptor(sw, constraint, ElementType.TYPE,
-          convertConstraintOriginEnum(constraintHibernate.getDefinedOn()),
-          constraintDescriptorVar("this", count++));
+      if (areConstraintDescriptorGroupsValid(constraint)) {
+        writeConstraintDescriptor(sw, constraint, ElementType.TYPE,
+            convertConstraintOriginEnum(constraintHibernate.getDefinedOn()),
+            constraintDescriptorVar("this", count++));
+      }
     }
 
     // Now write the BeanDescriptor after we already have the
@@ -1266,10 +1305,13 @@
 
     // myProperty_c0,
     // myProperty_c1 );
-    int size = p.getConstraintDescriptors().size();
-    for (int i = 0; i < size; i++) {
-      sw.println(","); // Print the , for the previous line
-      sw.print(constraintDescriptorVar(p.getPropertyName(), i));
+    int count = 0;
+    for (ConstraintDescriptor<?> constraint : p.getConstraintDescriptors()) {
+      if (areConstraintDescriptorGroupsValid(constraint)) {
+        sw.println(","); // Print the , for the previous line
+        sw.print(constraintDescriptorVar(p.getPropertyName(), count));
+        count++;
+      }
     }
     sw.println(");");
 
@@ -1932,31 +1974,33 @@
       Set<Object> includedAnnotations = Sets.newHashSet();
       int count = 0;
       for (ConstraintDescriptor<?> constraint : p.getConstraintDescriptors()) {
-        Object annotation = constraint.getAnnotation();
-        if (hasMatchingAnnotation(p, useField, constraint)) {
-          String constraintDescriptorVar = constraintDescriptorVar(p.getPropertyName(), count);
-          if (!includedAnnotations.contains(annotation)) {
-            if (useField) {
-              writeValidateConstraint(sw, p, elementClass, constraint, constraintDescriptorVar);
+        if (areConstraintDescriptorGroupsValid(constraint)) {
+          Object annotation = constraint.getAnnotation();
+          if (hasMatchingAnnotation(p, useField, constraint)) {
+            String constraintDescriptorVar = constraintDescriptorVar(p.getPropertyName(), count);
+            if (!includedAnnotations.contains(annotation)) {
+              if (useField) {
+                writeValidateConstraint(sw, p, elementClass, constraint, constraintDescriptorVar);
+              } else {
+                // The annotation hasn't been looked at twice (yet) and we are validating a getter
+                // Write the call if only the getter has this constraint applied to it
+                boolean hasField = beanHelper.hasField(p);
+                if (!hasField ||
+                    (hasField && !hasMatchingAnnotation(p, true, constraint))) {
+                  writeValidateConstraint(sw, p, elementClass, constraint, constraintDescriptorVar);
+                }
+              }
             } else {
-              // The annotation hasn't been looked at twice (yet) and we are validating a getter
-              // Write the call if only the getter has this constraint applied to it
-              boolean hasField = beanHelper.hasField(p);
-              if (!hasField ||
-                  (hasField && !hasMatchingAnnotation(p, true, constraint))) {
+              // The annotation has been looked at once already during this validate property call
+              // so we know the field and the getter are both annotated with the same constraint.
+              if (!useField) {
                 writeValidateConstraint(sw, p, elementClass, constraint, constraintDescriptorVar);
               }
             }
-          } else {
-            // The annotation has been looked at once already during this validate property call
-            // so we know the field and the getter are both annotated with the same constraint.
-            if (!useField) {
-              writeValidateConstraint(sw, p, elementClass, constraint, constraintDescriptorVar);
-            }
+            includedAnnotations.add(annotation);
           }
-          includedAnnotations.add(annotation);
+          count++;
         }
-        count++;
       }
       // }
       sw.outdent();
diff --git a/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java b/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java
index 7ff981b..43b71de 100644
--- a/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java
+++ b/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java
@@ -39,15 +39,18 @@
 public final class ValidatorGenerator extends Generator {
 
   private final BeanHelperCache cache;
+  private Class<?>[] validGroups;
 
   // called by the compiler via reflection
   public ValidatorGenerator() {
     this.cache = new BeanHelperCache();
+    this.validGroups = new Class<?>[]{ };
   }
 
   // called from tests
-  public ValidatorGenerator(BeanHelperCache cache) {
+  public ValidatorGenerator(BeanHelperCache cache, Class<?>[] validGroups) {
     this.cache = cache;
+    this.validGroups = validGroups;
   }
 
   @Override
@@ -110,6 +113,8 @@
       throw new UnableToCompleteException();
     }
 
+    this.validGroups = gwtValidation.groups();
+
     TreeLogger validatorLogger = logger.branch(TreeLogger.DEBUG,
         "Generating Validator for  '" + validatorType.getQualifiedSourceName()
             + "'", null);
@@ -136,7 +141,7 @@
     }
 
     AbstractCreator creator = new GwtSpecificValidatorCreator(validatorType,
-        beanType, beanHelper, logger, context, cache);
+        beanType, beanHelper, logger, context, cache, validGroups);
     return creator.create();
   }
 
diff --git a/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java b/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
index 8ec3640..31dcc50 100644
--- a/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
+++ b/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
@@ -18,6 +18,7 @@
 import com.google.gwt.junit.tools.GWTTestSuite;
 import com.google.gwt.validation.example.client.AuthorTest;
 import com.google.gwt.validation.example.client.BookTest;
+import com.google.gwt.validation.example.client.NotSpecifiedGroupsTest;
 
 import junit.framework.Test;
 
@@ -30,6 +31,7 @@
         "Validation Example tests that require GWT");
     suite.addTestSuite(AuthorTest.class);
     suite.addTestSuite(BookTest.class);
+    suite.addTestSuite(NotSpecifiedGroupsTest.class);
     return suite;
   }
 
diff --git a/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java b/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java
index 4aae839..0b926a5 100644
--- a/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java
+++ b/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java
@@ -41,7 +41,7 @@
    * client.
    */
   @GwtValidation(
-      value = {Author.class, Book.class},
+      value = {Author.class, Book.class, NotSpecifiedGroupsTest.MyClass.class},
       groups = {Default.class, ClientGroup.class})
   public interface GwtValidator extends Validator {
   }
diff --git a/user/test/com/google/gwt/validation/example/client/NotSpecifiedGroupsTest.java b/user/test/com/google/gwt/validation/example/client/NotSpecifiedGroupsTest.java
new file mode 100644
index 0000000..0c67824
--- /dev/null
+++ b/user/test/com/google/gwt/validation/example/client/NotSpecifiedGroupsTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012 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.validation.example.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.validation.example.client.ExampleValidatorFactory.ServerGroup;
+
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.constraints.NotNull;
+
+/**
+ * Tests used to verify that constraints belonging to a group which is not specified in the
+ * {@link com.google.gwt.validation.client.GwtValidation &#064;GwtValidation}
+ * are not considered (and are not compiled).
+ */
+public class NotSpecifiedGroupsTest extends GWTTestCase {
+
+  private Validator validator;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.validation.example.ValidationExample";
+  }
+
+  public void testConstraintsNotInSpecifiedGroupsAreNotConsidered() {
+    MyClass obj = new MyClass();
+    Set<ConstraintViolation<MyClass>> violations = validator.validate(obj);
+    assertEquals(1, violations.size());
+  }
+
+  @Override
+  protected final void gwtSetUp() throws Exception {
+    super.gwtSetUp();
+    validator = Validation.buildDefaultValidatorFactory().getValidator();
+  }
+
+  /**
+   * Used for testing client/server constraints via groups.
+   */
+  @ServerConstraint(groups = ServerGroup.class)
+  public static class MyClass {
+    @NotNull
+    public String name;
+  }
+}
diff --git a/user/test/com/google/gwt/validation/example/client/ServerConstraint.java b/user/test/com/google/gwt/validation/example/client/ServerConstraint.java
new file mode 100644
index 0000000..65f7c95
--- /dev/null
+++ b/user/test/com/google/gwt/validation/example/client/ServerConstraint.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 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.validation.example.client;
+
+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.ElementType.TYPE;
+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;
+
+/**
+ * A constraint which should not compile in client-side GWT validation.
+ */
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE})
+@Retention(RUNTIME)
+@Documented
+@Constraint(validatedBy = {ServerValidator.class})
+public @interface ServerConstraint {
+  String message() default "Not valid at the server";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/validation/example/client/ServerValidator.java b/user/test/com/google/gwt/validation/example/client/ServerValidator.java
new file mode 100644
index 0000000..7fb497f
--- /dev/null
+++ b/user/test/com/google/gwt/validation/example/client/ServerValidator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 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.validation.example.client;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * Validates server-side constraints. Will not compile on GWT.
+ */
+public class ServerValidator
+    implements ConstraintValidator<ServerConstraint, NotSpecifiedGroupsTest.MyClass> {
+
+  @Override
+  public void initialize(ServerConstraint constraintAnnotation) {
+    // Here I do something that will not compile on GWT
+    @SuppressWarnings("unused")
+    Method[] methods = constraintAnnotation.getClass().getMethods();
+  }
+
+  @Override
+  public boolean isValid(NotSpecifiedGroupsTest.MyClass obj, ConstraintValidatorContext context) {
+    @SuppressWarnings("unused")
+    Field[] fields = obj.getClass().getDeclaredFields();
+    return false;
+  }
+}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceContainingDefaultValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceContainingDefaultValidatorFactory.java
index bf18bb5..d958005 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceContainingDefaultValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceContainingDefaultValidatorFactory.java
@@ -23,6 +23,7 @@
 import org.hibernate.jsr303.tck.tests.constraints.groups.DefaultGroupRedefinitionTest.AddressWithDefaultInGroupSequence;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * ValidatorFactory for
@@ -35,7 +36,8 @@
    * Validator for
    * {@link DefaultGroupRedefinitionTest#testGroupSequenceContainingDefault()}
    */
-  @GwtValidation(value = {AddressWithDefaultInGroupSequence.class})
+  @GwtValidation(value = {AddressWithDefaultInGroupSequence.class},
+      groups = {Default.class, Address.HighLevelCoherence.class, Address.Complete.class})
   public static interface GroupSequenceContainingDefaultValidator extends
       Validator {
   }
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceWithNoImplicitDefaultGroupValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceWithNoImplicitDefaultGroupValidatorFactory.java
index 6dc43ce..15acfd6 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceWithNoImplicitDefaultGroupValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/GroupSequenceWithNoImplicitDefaultGroupValidatorFactory.java
@@ -23,6 +23,7 @@
 import org.hibernate.jsr303.tck.tests.constraints.groups.DefaultGroupRedefinitionTest.AddressWithDefaultInGroupSequence;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * ValidatorFactory for
@@ -35,7 +36,8 @@
    * Validator for
    * {@link DefaultGroupRedefinitionTest#testGroupSequenceWithNoImplicitDefaultGroup()}
    */
-  @GwtValidation(value = {AddressWithDefaultInGroupSequence.class})
+  @GwtValidation(value = {AddressWithDefaultInGroupSequence.class},
+      groups = {Default.class, Address.HighLevelCoherence.class, Address.Complete.class})
   public static interface TestValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/TckTestValidatorFactory.java
index 9db324a..6bfe8e5 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/TckTestValidatorFactory.java
@@ -35,8 +35,8 @@
       Address.class, Animal.class, Book.class, Car.class, Order.class,
         User.class},
       groups = {Default.class, User.Billable.class, User.BuyInOneClick.class, User.Optional.class, 
-        CyclicGroupSequence.class, Auditable.class, 
-        First.class, Second.class, Last.class, Book.All.class})
+        CyclicGroupSequence.class, Auditable.class, First.class, Second.class, Last.class,
+        Book.All.class, Address.HighLevelCoherence.class, Address.Complete.class, Car.Test.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequenceisolation/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequenceisolation/TckTestValidatorFactory.java
index 58764fe..ef8e7af 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequenceisolation/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequenceisolation/TckTestValidatorFactory.java
@@ -31,7 +31,7 @@
    * Marker Interface to {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {B1.class, B2.class, B3.class, C.class, E.class},
-      groups = {Heavy.class, Minimal.class})
+      groups = {Heavy.class, Minimal.class, Later.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java
index f7a1d6d..e512a49 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java
@@ -20,6 +20,8 @@
 import com.google.gwt.validation.client.GwtValidation;
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
+import org.hibernate.jsr303.tck.tests.metadata.Person.PersonValidation;
+
 import javax.validation.Validator;
 import javax.validation.groups.Default;
 
@@ -35,7 +37,7 @@
         Account.class, Customer.class, Man.class, Order.class, Person.class,
         SubClass.class, SuperClass.class, UnconstraintEntity.class},
       groups = {Default.class, SubClass.DefaultGroup.class, SuperClass.BasicGroup.class,
-        SuperClass.InheritedGroup.class, SuperClass.UnusedGroup.class})
+        SuperClass.InheritedGroup.class, SuperClass.UnusedGroup.class, PersonValidation.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java b/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
index acdceb1..8303e1e 100644
--- a/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
+++ b/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
@@ -41,18 +41,19 @@
   private BeanHelperCache cache;
   private StandardGeneratorContext context;
   private TreeLogger failOnErrorLogger;
+  private Class<?>[] validGroups;
 
   protected void assertBeanValidatorFailsToCompile(
       Class<? extends Validator> validatorClass, Class<?> beanType,
       Class<? extends ValidationException> expectedException,
       String expectedMessage) throws UnableToCompleteException {
-    ValidatorGenerator generator = new ValidatorGenerator(cache);
+    ValidatorGenerator generator = new ValidatorGenerator(cache, validGroups);
     generator.generate(failOnErrorLogger, context,
         validatorClass.getCanonicalName());
     context.finish(failOnErrorLogger);
 
     // Now create the validator that is going to fail
-    ValidatorGenerator specificGenerator = new ValidatorGenerator(cache);
+    ValidatorGenerator specificGenerator = new ValidatorGenerator(cache, validGroups);
     String beanHelperName = createBeanHelper(beanType);
     assertUnableToComplete(expectedException, expectedMessage,
         specificGenerator, beanHelperName);
@@ -62,7 +63,7 @@
       Class<? extends Validator> validatorClass,
       Class<? extends ValidationException> expectedException,
       String expectedMessage) {
-    ValidatorGenerator generator = new ValidatorGenerator(cache);
+    ValidatorGenerator generator = new ValidatorGenerator(cache, validGroups);
     assertUnableToComplete(expectedException, expectedMessage, generator,
         validatorClass.getCanonicalName());
   }
@@ -73,6 +74,7 @@
     cache = new BeanHelperCache();
     failOnErrorLogger = createFailOnErrorLogger();
     context = createGeneratorContext(getTckTestModuleName(), failOnErrorLogger);
+    validGroups = new Class<?>[]{ };
   }
 
   private void assertUnableToComplete(