Integrate r11165, r11166, r11170, r11176, r11177, r11179, r11180, r11181 and r11186 into releases/2.5.

Review by: rdayal@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.5@11275 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTestBase.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTestBase.java
index e2cd44a..86c5580 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTestBase.java
@@ -73,6 +73,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -1168,8 +1169,8 @@
     addTestResource(CU_Throwable);
     addTestResource(CU_MethodsAndParams);
     buildTypeOracle();
-    JClassType[] types = typeOracle.getTypes();
-    assertEquals(3, types.length);
+    // Throwable has nested classes in JDK 7, so we need to ignore them
+    checkGetTypes("Methods", "Object", "Throwable");
   }
 
   public void testOuterInner() throws TypeOracleException {
@@ -1313,6 +1314,26 @@
     }
   }
 
+  private void checkGetTypes(String... expectedOuterClassNames) {
+    Set<String> expected = new HashSet<String>();
+    expected.addAll(Arrays.asList(expectedOuterClassNames));
+
+    Set<String> found = new HashSet<String>();
+
+    for (JClassType type : typeOracle.getTypes()) {
+      String name = type.getName();
+      if (name.indexOf('.') > 0) {
+        name = name.substring(0, name.indexOf('.'));
+      }
+      if (!expected.contains(name)) {
+        fail("getTypes() returned an unexpected class: " + type.getName());
+      }
+      found.add(name);
+    }
+
+    assertEquals(expected, found);
+  }
+
   private void register(String qualifiedTypeName, CheckedJavaResource cup) {
     assertFalse(publicTypeNameToTestCupMap.containsKey(qualifiedTypeName));
     publicTypeNameToTestCupMap.put(qualifiedTypeName, cup);
diff --git a/user/src/com/google/gwt/core/client/JsonUtils.java b/user/src/com/google/gwt/core/client/JsonUtils.java
index 7088266..b1af086 100644
--- a/user/src/com/google/gwt/core/client/JsonUtils.java
+++ b/user/src/com/google/gwt/core/client/JsonUtils.java
@@ -28,7 +28,7 @@
    * eval(). Control characters, quotes and backslashes are not affected.
    */
   public static native String escapeJsonForEval(String toEscape) /*-{
-    var s = toEscape.replace(/[\xad\u0600-\u0603\u06dd\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb]/g, function(x) {
+    var s = toEscape.replace(/[\xad\u0600-\u0603\u06dd\u070f\u17b4\u17b5\u200b-\u200f\u2028-\u202e\u2060-\u2064\u206a-\u206f\ufeff\ufff9-\ufffb]/g, function(x) {
       return @com.google.gwt.core.client.JsonUtils::escapeChar(Ljava/lang/String;)(x);
     });
     return s;
@@ -38,7 +38,7 @@
    * Returns a quoted, escaped JSON String.
    */
   public static native String escapeValue(String toEscape) /*-{
-    var s = toEscape.replace(/[\x00-\x1f\xad\u0600-\u0603\u06dd\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb"\\]/g, function(x) {
+    var s = toEscape.replace(/[\x00-\x1f\xad\u0600-\u0603\u06dd\u070f\u17b4\u17b5\u200b-\u200f\u2028-\u202e\u2060-\u2064\u206a-\u206f\ufeff\ufff9-\ufffb"\\]/g, function(x) {
       return @com.google.gwt.core.client.JsonUtils::escapeChar(Ljava/lang/String;)(x);
     });
     return "\"" + s + "\"";
@@ -149,6 +149,7 @@
     out[0x70f] = '\\u070f'; // Syriac abbreviation mark
     out[0x17b4] = '\\u17b4'; // Khmer vowel inherent aq
     out[0x17b5] = '\\u17b5'; // Khmer vowel inherent aa
+    out[0x200b] = '\\u200b'; // Zero width space
     out[0x200c] = '\\u200c'; // Zero width non-joiner
     out[0x200d] = '\\u200d'; // Zero width joiner
     out[0x200e] = '\\u200e'; // Left-to-right mark
@@ -164,6 +165,7 @@
     out[0x2061] = '\\u2061'; // Function application
     out[0x2062] = '\\u2062'; // Invisible times
     out[0x2063] = '\\u2063'; // Invisible separator
+    out[0x2064] = '\\u2064'; // Invisible plus
     out[0x206a] = '\\u206a'; // Inhibit symmetric swapping
     out[0x206b] = '\\u206b'; // Activate symmetric swapping
     out[0x206c] = '\\u206c'; // Inherent Arabic form shaping
diff --git a/user/src/com/google/gwt/resources/css/GenerateCssAst.java b/user/src/com/google/gwt/resources/css/GenerateCssAst.java
index 337e47d..0810ba9 100644
--- a/user/src/com/google/gwt/resources/css/GenerateCssAst.java
+++ b/user/src/com/google/gwt/resources/css/GenerateCssAst.java
@@ -36,6 +36,7 @@
 import com.google.gwt.resources.css.ast.HasNodes;
 import com.google.gwt.resources.css.ast.HasProperties;
 import com.google.gwt.resources.css.ast.CssProperty.DotPathValue;
+import com.google.gwt.resources.css.ast.CssProperty.FunctionValue;
 import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
 import com.google.gwt.resources.css.ast.CssProperty.ListValue;
 import com.google.gwt.resources.css.ast.CssProperty.NumberValue;
@@ -1052,11 +1053,10 @@
           return new IdentValue(s);
 
         } else {
-          // Just return a String representation of the original value
           List<Value> parameters = new ArrayList<Value>();
           extractValueOf(parameters, value.getParameters());
-          return new IdentValue(value.getFunctionName() + "("
-              + join(parameters, "") + ")");
+          return new FunctionValue(value.getFunctionName(),
+              new ListValue(parameters));
         }
       }
       case LexicalUnit.SAC_INHERIT:
diff --git a/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java b/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java
index b74b4bf..885a2b4 100644
--- a/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java
+++ b/user/src/com/google/gwt/resources/css/SubstitutionReplacer.java
@@ -23,19 +23,19 @@
 import com.google.gwt.resources.css.ast.CssCompilerException;
 import com.google.gwt.resources.css.ast.CssDef;
 import com.google.gwt.resources.css.ast.CssProperty;
-import com.google.gwt.resources.css.ast.CssUrl;
-import com.google.gwt.resources.css.ast.CssVisitor;
 import com.google.gwt.resources.css.ast.CssProperty.DotPathValue;
 import com.google.gwt.resources.css.ast.CssProperty.ExpressionValue;
+import com.google.gwt.resources.css.ast.CssProperty.FunctionValue;
 import com.google.gwt.resources.css.ast.CssProperty.IdentValue;
 import com.google.gwt.resources.css.ast.CssProperty.ListValue;
 import com.google.gwt.resources.css.ast.CssProperty.Value;
+import com.google.gwt.resources.css.ast.CssUrl;
+import com.google.gwt.resources.css.ast.CssVisitor;
 import com.google.gwt.resources.ext.ResourceContext;
 import com.google.gwt.resources.ext.ResourceGeneratorUtil;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Map;
 
 /**
@@ -62,21 +62,33 @@
       // Nothing to do
       return;
     }
+    x.setValue(substituteDefs(x.getValues()));
+  }
 
-    List<Value> values = new ArrayList<Value>(x.getValues().getValues());
-
-    for (ListIterator<Value> i = values.listIterator(); i.hasNext();) {
-      IdentValue v = i.next().isIdentValue();
-
-      if (v == null) {
-        // Don't try to substitute into anything other than idents
+  private ListValue substituteDefs(ListValue listValue) {
+    List<Value> result = new ArrayList<Value>(listValue.getValues().size());
+    for (Value val : listValue.getValues()) {
+      if (val.isFunctionValue() != null) {
+        // Recursively perform substitution on a function's values
+        FunctionValue fnVal = val.isFunctionValue();
+        ListValue newVals = substituteDefs(fnVal.getValues());
+        result.add(new FunctionValue(fnVal.getName(), newVals));
         continue;
       }
 
-      String value = v.getIdent();
-      CssDef def = substitutions.get(value);
+      IdentValue maybeIdent = val.isIdentValue();
+      if (maybeIdent == null) {
+        // Not an ident, append as-is to result
+        result.add(val);
+        continue;
+      }
+
+      String identStr = maybeIdent.getIdent();
+      CssDef def = substitutions.get(identStr);
 
       if (def == null) {
+        // No substitution found, append as-is to result
+        result.add(val);
         continue;
       } else if (def instanceof CssUrl) {
         assert def.getValues().size() == 1;
@@ -99,16 +111,13 @@
         expression.append("\"url('\" + ");
         expression.append(instance).append(".getUrl()");
         expression.append(" + \"')\"");
-        i.set(new ExpressionValue(expression.toString()));
-
+        result.add(new ExpressionValue(expression.toString()));
       } else {
-        i.remove();
         for (Value defValue : def.getValues()) {
-          i.add(defValue);
+          result.add(defValue);
         }
       }
     }
-
-    x.setValue(new ListValue(values));
+    return new ListValue(result);
   }
 }
diff --git a/user/src/com/google/gwt/resources/css/ast/CssProperty.java b/user/src/com/google/gwt/resources/css/ast/CssProperty.java
index a3eff21..6fe0da5 100644
--- a/user/src/com/google/gwt/resources/css/ast/CssProperty.java
+++ b/user/src/com/google/gwt/resources/css/ast/CssProperty.java
@@ -130,6 +130,49 @@
   }
 
   /**
+   * Represents a CSS function value.
+   */
+  public static class FunctionValue extends Value {
+    private final String name;
+    private final ListValue values;
+
+    public FunctionValue(String name, ListValue values) {
+      this.name = name;
+      this.values = values;
+    }
+
+    @Override
+    public String getExpression() {
+      // "{name}(" + {valuesExpr} + ")"
+      return String.format("\"%s(\" + %s + \")\"",
+          Generator.escape(name), values.getExpression());
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public ListValue getValues() {
+      return values;
+    }
+
+    @Override
+    public FunctionValue isFunctionValue() {
+      return this;
+    }
+
+    @Override
+    public boolean isStatic() {
+      return values.isStatic();
+    }
+
+    @Override
+    public String toCss() {
+      return name + "(" + values.toCss() + ")";
+    }
+  }
+
+  /**
    * Represents an identifier in the CSS source.
    */
   public static class IdentValue extends Value {
@@ -217,9 +260,16 @@
     public String toCss() {
       StringBuilder sb = new StringBuilder();
       for (Value v : values) {
-        sb.append(" ").append(v.toCss());
+        if (v.isSpaceRequired()) {
+          sb.append(" ");
+        }
+        sb.append(v.toCss());
       }
-      return sb.substring(1);
+      if (sb.charAt(0) == ' ') {
+        return sb.substring(1);
+      } else {
+        return sb.toString();
+      }
     }
   }
 
@@ -389,6 +439,10 @@
       return null;
     }
 
+    public FunctionValue isFunctionValue() {
+      return null;
+    }
+
     public IdentValue isIdentValue() {
       return null;
     }
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index bb7ab81..20e2e6e 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -823,7 +823,7 @@
   }
 
   /**
-   * Returns a {@link TakesValueEditor} backed by the DateBox.
+   * Returns a {@link TakesValueEditor} backed by the SuggestBox.
    */
   public LeafValueEditor<String> asEditor() {
     if (editor == null) {
diff --git a/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java b/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java
index 4eb1e3d..e899c06 100644
--- a/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java
+++ b/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java
@@ -166,7 +166,7 @@
    * @return the day of month formatter
    */
   protected DateTimeFormat getDayOfMonthFormatter() {
-    return DateTimeFormat.getFormat(PredefinedFormat.DAY);
+    return DateTimeFormat.getFormat("d");
   }
 
   /**
diff --git a/user/src/com/google/gwt/validation/client/ConstraintOrigin.java b/user/src/com/google/gwt/validation/client/ConstraintOrigin.java
new file mode 100644
index 0000000..41c0da7
--- /dev/null
+++ b/user/src/com/google/gwt/validation/client/ConstraintOrigin.java
@@ -0,0 +1,37 @@
+/*
+ * 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.validation.client;
+
+/**
+ * <strong>EXPERIMENTAL</strong> and subject to change. Do not use this in
+ * production code.
+ * <p>
+ * Visibility looked at when discovering constraints.
+ * <p>
+ * Exactly the same as the
+ * <a href="http://docs.jboss.org/hibernate/validator/4.3/api/org/hibernate/validator/internal/metadata/core/ConstraintOrigin.html">
+ * Hibernate implementation</a>.
+ */
+public enum ConstraintOrigin {
+  /**
+   * Constraint is defined on the root class
+   */
+  DEFINED_LOCALLY,
+  /**
+   * Constraint is defined in a super-class or interface of the root class.
+   */
+  DEFINED_IN_HIERARCHY
+}
diff --git a/user/src/com/google/gwt/validation/client/GroupInheritanceMap.java b/user/src/com/google/gwt/validation/client/GroupInheritanceMap.java
new file mode 100644
index 0000000..f517670
--- /dev/null
+++ b/user/src/com/google/gwt/validation/client/GroupInheritanceMap.java
@@ -0,0 +1,176 @@
+/*
+ * 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.client;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Stack;
+
+import javax.validation.groups.Default;
+
+
+/**
+ * <strong>EXPERIMENTAL</strong> and subject to change. Do not use this in
+ * production code.
+ * <p>
+ * Contains all the information known about the inheritance information for validation groups.
+ */
+public class GroupInheritanceMap {
+
+  /**
+   * Builder for {@link GroupInheritanceMap}
+   */
+  public static class Builder {
+    Map<Class<?>, Set<Class<?>>> mapping;
+
+    private Builder() {
+      mapping = new HashMap<Class<?>, Set<Class<?>>>();
+      addGroup(Default.class);
+    }
+
+    /**
+     * Adds a group to the inheritance map. May optionally include parents of the group.
+     * @param group The validation group to add.
+     * @param parents A list of validation groups which {@code group} extends. Can be empty if the
+     * group contains no parents.
+     */
+    public Builder addGroup(Class<?> group, Class<?>... parents) {
+      mapping.put(group, new HashSet<Class<?>>(Arrays.asList(parents)));
+      return this;
+    }
+    
+    public GroupInheritanceMap build() {
+      return new GroupInheritanceMap(mapping);
+    }
+  }
+
+  /**
+   * Creates a builder populated only with the {@link Default} group.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private final Map<Class<?>, Set<Class<?>>> mapping;
+
+  private GroupInheritanceMap(Map<Class<?>, Set<Class<?>>> mapping) {
+    this.mapping = Collections.unmodifiableMap(mapping);
+  }
+
+  /**
+   * Checks if a given group has been added to the map.
+   */
+  public boolean containsGroup(Class<?> group) {
+    return mapping.containsKey(group);
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (this == other) {
+      return true;
+    }
+    if (!(other instanceof GroupInheritanceMap)) {
+      return false;
+    }
+    GroupInheritanceMap otherObj = (GroupInheritanceMap)other;
+    return mapping.equals(otherObj.mapping);
+  }
+
+  /**
+   * Finds all of the validation groups extended by an intial set of groups.
+   * @param baseGroups The initial set of groups to find parents of. These groups must have been 
+   * added to the inheritance map already.
+   * @return A unified set of groups and their parents.
+   * @throws IllegalArgumentException If an initial group has not been added to the map before
+   * calling this method.
+   */
+  public Set<Class<?>> findAllExtendedGroups(Collection<Class<?>> baseGroups)
+      throws IllegalArgumentException {
+    Set<Class<?>> found = new HashSet<Class<?>>();
+    Stack<Class<?>> remaining = new Stack<Class<?>>();
+    // initialize
+    for (Class<?> group : baseGroups) {
+      if (!mapping.containsKey(group)) {
+        throw new IllegalArgumentException("The collection of groups contains a group which" +
+            " was not added to the map. Be sure to call addGroup() for all groups first.");
+      }
+      remaining.push(group);
+    }
+    // traverse
+    Class<?> current;
+    Set<Class<?>> superInterfaces;
+    while (!remaining.isEmpty()) {
+      current = remaining.pop();
+      found.add(current);
+      superInterfaces = mapping.get(current);
+      for (Class<?> parent : superInterfaces) {
+        if (!found.contains(parent)) {
+          remaining.push(parent);
+        }
+      }
+    }
+    return found;
+  }
+
+  /**
+   * Recursively gets all of the groups in the map (children and parents alike) in one flat set.
+   */
+  public Set<Class<?>> getAllGroups() {
+    Set<Class<?>> allGroups = new HashSet<Class<?>>();
+    for (Map.Entry<Class<?>, Set<Class<?>>> entry : mapping.entrySet()) {
+      allGroups.add(entry.getKey());
+      allGroups.addAll(entry.getValue());
+    }
+    return allGroups;
+  }
+
+  /**
+   * If the group has been added to the map then its parent groups (of one level above) are
+   * retrieved. Otherwise null is returned.
+   * 
+   * @see #containsGroup(Class)
+   * @see #findAllExtendedGroups(Collection)
+   */
+  public Set<Class<?>> getParentsOfGroup(Class<?> group) {
+    return mapping.get(group);
+  }
+
+  /**
+   * Returns all of the groups added to the map (but not their parents).
+   */
+  public Set<Class<?>> getRootGroups() {
+    return mapping.keySet();
+  }
+
+  @Override
+  public int hashCode() {
+    return mapping.hashCode();
+  }
+
+  public boolean isEmpty() {
+    return mapping.isEmpty();
+  }
+
+  @Override
+  public String toString() {
+    return mapping.toString();
+  }
+}
diff --git a/user/src/com/google/gwt/validation/client/GwtValidation.java b/user/src/com/google/gwt/validation/client/GwtValidation.java
index 30b5d7a..53bb07e 100644
--- a/user/src/com/google/gwt/validation/client/GwtValidation.java
+++ b/user/src/com/google/gwt/validation/client/GwtValidation.java
@@ -22,6 +22,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
+import javax.validation.groups.Default;
+
 /**
  * <strong>EXPERIMENTAL</strong> and subject to change. Do not use this in
  * production code.
@@ -89,9 +91,10 @@
 
   /**
    * The list of Groups which can be processed by the annotated
-   * {@code Validator}, empty means all groups.
+   * {@code Validator}. The default value is {@link Default}.
+   * An empty array is illegal.
    */
-  Class<?>[] groups() default {};
+  Class<?>[] groups() default {Default.class};
 
   /**
    * The list of Classes which can be validated by the annotated
diff --git a/user/src/com/google/gwt/validation/client/impl/AbstractGwtSpecificValidator.java b/user/src/com/google/gwt/validation/client/impl/AbstractGwtSpecificValidator.java
index 925fbab..4dbc1b4 100644
--- a/user/src/com/google/gwt/validation/client/impl/AbstractGwtSpecificValidator.java
+++ b/user/src/com/google/gwt/validation/client/impl/AbstractGwtSpecificValidator.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import java.lang.annotation.Annotation;
 import java.util.Arrays;
 import java.util.Collection;
@@ -98,11 +100,14 @@
     ConstraintValidatorContextImpl<A, V> constraintValidatorContext =
         context.createConstraintValidatorContext(constraintDescriptor);
 
-    Set<Class<?>> constraintGroup = constraintDescriptor.getGroups();
+    GroupInheritanceMap groupInheritanceMap = context.getValidator().getGroupInheritanceMap();
+    // check against the groups passed in as well as their parent (super) interfaces
+    Set<Class<?>> extendedGroups = groupInheritanceMap.findAllExtendedGroups(Arrays.asList(groups));
+    Set<Class<?>> constraintGroups = constraintDescriptor.getGroups();
 
     // check groups requested are in the set of constraint groups (including the implicit group)
-    if (!containsAny(groups, constraintGroup)
-        && !Arrays.asList(groups).contains(getConstraints().getElementClass())) {
+    if (!containsAny(extendedGroups, constraintGroups)
+        && !Arrays.asList(groups).contains(getConstraints(groupInheritanceMap).getElementClass())) {
       return false;
     }
 
@@ -135,7 +140,7 @@
     }
   }
 
-  private <T> boolean containsAny(T[] left, Collection<T> right) {
+  private <T> boolean containsAny(Collection<T> left, Collection<T> right) {
     for (T t : left) {
       if (right.contains(t)) {
         return true;
diff --git a/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java b/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java
index c49f8aa..0cdd850 100644
--- a/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java
+++ b/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java
@@ -15,8 +15,9 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Set;
 
 import javax.validation.ConstraintValidatorFactory;
@@ -37,17 +38,29 @@
 public abstract class AbstractGwtValidator implements Validator {
 
   private final Set<Class<?>> validGroups;
+  private final GroupInheritanceMap groupInheritanceMap;
   private ConstraintValidatorFactory contraintValidatorFactory;
   private MessageInterpolator messageInterpolator;
   private TraversableResolver traversableResolver;
 
   /**
-   *
-   * @param groups list of valid groups. An empty list defaults to just the
-   *          {@link javax.validation.groups.Default} group.
+   * Creates a validator initialized with the default group inheritance map.
+   * @see #AbstractGwtValidator(GroupInheritanceMap)
    */
-  public AbstractGwtValidator(Class<?>... groups) {
-    validGroups = new HashSet<Class<?>>(Arrays.asList(groups));
+  public AbstractGwtValidator() {
+    this(GroupInheritanceMap.builder().build());
+  }
+
+  /**
+   * @param groupInheritanceMap Map of groups to the groups' parents.
+   */
+  public AbstractGwtValidator(GroupInheritanceMap groupInheritanceMap) {
+    validGroups = groupInheritanceMap.getAllGroups();
+    this.groupInheritanceMap = groupInheritanceMap;
+  }
+
+  public GroupInheritanceMap getGroupInheritanceMap() {
+    return groupInheritanceMap;
   }
 
   public void init(ConstraintValidatorFactory factory,
@@ -58,6 +71,7 @@
     this.traversableResolver = traversableResolver;
   }
 
+  @Override
   public <T> T unwrap(Class<T> type) {
     throw new ValidationException();
   }
@@ -67,9 +81,7 @@
       throws ValidationException;
 
   protected void checkGroups(Class<?>... groups) {
-    // an empty list of valid groups means all groups are valid.
-    if (!validGroups.isEmpty()
-        && !validGroups.containsAll(Arrays.asList(groups))) {
+    if (!validGroups.containsAll(Arrays.asList(groups))) {
       throw new IllegalArgumentException(this.getClass()
           + " only processes the following groups " + validGroups);
     }
diff --git a/user/src/com/google/gwt/validation/client/impl/ConstraintDescriptorImpl.java b/user/src/com/google/gwt/validation/client/impl/ConstraintDescriptorImpl.java
index 1baad70..63b160a 100644
--- a/user/src/com/google/gwt/validation/client/impl/ConstraintDescriptorImpl.java
+++ b/user/src/com/google/gwt/validation/client/impl/ConstraintDescriptorImpl.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.ConstraintOrigin;
+
 import java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
 import java.util.Arrays;
@@ -53,6 +55,7 @@
         new HashSet<ConstraintDescriptor<?>>();
     private boolean reportAsSingleViolation;
     private ElementType elementType;
+    private ConstraintOrigin definedOn;
 
     public Builder<T> addComposingConstraint(
         ConstraintDescriptor<?> composingConstraint) {
@@ -69,7 +72,8 @@
           attributes, //
           composingConstraints, //
           reportAsSingleViolation, //
-          elementType);
+          elementType, //
+          definedOn);
     }
 
     public Builder<T> setAnnotation(T annotation) {
@@ -94,7 +98,12 @@
       this.constraintValidatorClasses = constraintValidatorClasses;
       return this;
     }
-    
+
+    public Builder<T> setDefinedOn(ConstraintOrigin definedOn) {
+      this.definedOn = definedOn;
+      return this;
+    }
+
     public Builder<T> setElementType(ElementType elementType) {
       this.elementType = elementType;
       return this;
@@ -137,7 +146,8 @@
   private final Map<String, Object> attributes;
   private final Set<ConstraintDescriptor<?>> composingConstraints;
   private final boolean reportAsSingleViolation;
-  private ElementType elementType;
+  private final ElementType elementType;
+  private final ConstraintOrigin definedOn;
 
   private ConstraintDescriptorImpl(
       T annotation,
@@ -147,7 +157,8 @@
       Map<String, Object> attributes,
       Set<ConstraintDescriptor<?>> composingConstraints,
       boolean reportAsSingleViolation,
-      ElementType elementType) {
+      ElementType elementType,
+      ConstraintOrigin definedOn) {
     super();
     this.annotation = annotation;
     this.groups = groups;
@@ -157,36 +168,48 @@
     this.composingConstraints = composingConstraints;
     this.reportAsSingleViolation = reportAsSingleViolation;
     this.elementType = elementType;
+    this.definedOn = definedOn;
   }
 
+  @Override
   public T getAnnotation() {
     return annotation;
   }
 
+  @Override
   public Map<String, Object> getAttributes() {
     return attributes;
   }
 
+  @Override
   public Set<ConstraintDescriptor<?>> getComposingConstraints() {
     return composingConstraints;
   }
 
+  @Override
   public List<Class<? extends ConstraintValidator<T, ?>>> getConstraintValidatorClasses() {
     return constraintValidatorClasses;
   }
 
+  public ConstraintOrigin getDefinedOn() {
+    return definedOn;
+  }
+
   public ElementType getElementType() {
     return elementType;
   }
 
+  @Override
   public Set<Class<?>> getGroups() {
     return groups;
   }
 
+  @Override
   public Set<Class<? extends Payload>> getPayload() {
     return payload;
   }
 
+  @Override
   public boolean isReportAsSingleViolation() {
     return reportAsSingleViolation;
   }
diff --git a/user/src/com/google/gwt/validation/client/impl/ConstraintFinderImpl.java b/user/src/com/google/gwt/validation/client/impl/ConstraintFinderImpl.java
new file mode 100644
index 0000000..1b6f3c9
--- /dev/null
+++ b/user/src/com/google/gwt/validation/client/impl/ConstraintFinderImpl.java
@@ -0,0 +1,127 @@
+/*
+ * 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.client.impl;
+
+import com.google.gwt.validation.client.ConstraintOrigin;
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
+import java.lang.annotation.ElementType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.Scope;
+import javax.validation.metadata.ElementDescriptor.ConstraintFinder;
+
+/**
+ * <strong>EXPERIMENTAL</strong> and subject to change. Do not use this in
+ * production code.
+ * <p>
+ */
+public final class ConstraintFinderImpl implements ConstraintFinder {
+  private Set<ConstraintDescriptorImpl<?>> constraintDescriptors;
+  private GroupInheritanceMap groupInheritanceMap;
+  private List<Class<?>> groups;
+  private Set<ConstraintOrigin> definedInSet;
+  private Set<ElementType> elementTypes;
+
+  public ConstraintFinderImpl(GroupInheritanceMap groupInheritanceMap, 
+      Set<ConstraintDescriptorImpl<?>> constraintDescriptors) {
+    this.groupInheritanceMap = groupInheritanceMap;
+    this.constraintDescriptors = constraintDescriptors;
+    elementTypes = new HashSet<ElementType>();
+    elementTypes.add(ElementType.TYPE);
+    elementTypes.add(ElementType.METHOD);
+    elementTypes.add(ElementType.FIELD);
+    definedInSet = new HashSet<ConstraintOrigin>();
+    definedInSet.add(ConstraintOrigin.DEFINED_LOCALLY);
+    definedInSet.add(ConstraintOrigin.DEFINED_IN_HIERARCHY);
+    groups = Collections.emptyList();
+  }
+
+  @Override
+  public ConstraintFinder declaredOn(ElementType... types) {
+    elementTypes.clear();
+    elementTypes.addAll(Arrays.asList(types));
+    return this;
+  }
+
+  @Override
+  public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+    if (groupInheritanceMap == null) {
+      // sanity check - this could be null if the caller does not set a group inheritance map first
+      throw new IllegalStateException("ConstraintFinderImpl not initialized properly. A " +
+          "GroupInheritanceMap is required by GWT to properly find all constraint descriptors.");
+    }
+    Set<ConstraintDescriptor<?>> matchingDescriptors = new HashSet<ConstraintDescriptor<?>>();
+    findMatchingDescriptors(matchingDescriptors);
+    return Collections.unmodifiableSet(matchingDescriptors);
+  }
+
+  @Override
+  public boolean hasConstraints() {
+    return !getConstraintDescriptors().isEmpty();
+  }
+
+  @Override
+  public ConstraintFinder lookingAt(Scope scope) {
+    if (scope.equals(Scope.LOCAL_ELEMENT)) {
+      definedInSet.remove(ConstraintOrigin.DEFINED_IN_HIERARCHY);
+    }
+    return this;
+  }
+
+  @Override
+  public ConstraintFinder unorderedAndMatchingGroups(Class<?>... groups) {
+    this.groups = new ArrayList<Class<?>>(groups.length);
+    Collections.addAll(this.groups, groups);
+    return this;
+  }
+
+  private void addMatchingDescriptorsForGroup(Class<?> group,
+      Set<ConstraintDescriptor<?>> matchingDescriptors) {
+    for (ConstraintDescriptorImpl<?> descriptor : constraintDescriptors) {
+      if (definedInSet.contains(descriptor.getDefinedOn())
+          && elementTypes.contains(descriptor.getElementType())
+          && descriptor.getGroups().contains(group)) {
+        matchingDescriptors.add(descriptor);
+      }
+    }
+  }
+
+  private void findMatchingDescriptors(Set<ConstraintDescriptor<?>> matchingDescriptors) {
+    if (!groups.isEmpty()) {
+      // TODO(idol) The group sequence ordering will play a part here
+      Set<Class<?>> extendedGroups = groupInheritanceMap.findAllExtendedGroups(groups);
+      for (Class<?> group : extendedGroups) {
+        addMatchingDescriptorsForGroup(group, matchingDescriptors);
+      }
+    }
+    else {
+      for (ConstraintDescriptorImpl<?> descriptor : constraintDescriptors) {
+        if (definedInSet.contains(descriptor.getDefinedOn()) &&
+            elementTypes.contains(descriptor.getElementType())) {
+          matchingDescriptors.add(descriptor);
+        }
+      }
+    }
+  }
+
+}
diff --git a/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptor.java b/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptor.java
index be02d0a..a6bd79c 100644
--- a/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptor.java
+++ b/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptor.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import javax.validation.metadata.BeanDescriptor;
 
 /**
@@ -27,4 +29,5 @@
  * @param <T>
  */
 public interface GwtBeanDescriptor<T> extends BeanDescriptor {
+  void setGroupInheritanceMap(GroupInheritanceMap groupInheritanceMap);
 }
diff --git a/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptorImpl.java b/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptorImpl.java
index f569e4a..55199d9 100644
--- a/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptorImpl.java
+++ b/user/src/com/google/gwt/validation/client/impl/GwtBeanDescriptorImpl.java
@@ -15,7 +15,10 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import java.lang.annotation.Annotation;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -37,17 +40,17 @@
 public final class GwtBeanDescriptorImpl<T> implements GwtBeanDescriptor<T> {
 
   /**
-   * Builder for {@link GwtBeanDescriptors}.
+   * Builder for {@link GwtBeanDescriptor}s.
    *
    * @param <T> the bean Type
    */
   public static final class Builder<T> {
 
     private final Class<T> clazz;
-    private final Map<String, PropertyDescriptor> descriptorMap =
-        new HashMap<String, PropertyDescriptor>();
-    private final Set<ConstraintDescriptor<? extends Annotation>> constraints =
-        new HashSet<ConstraintDescriptor<? extends Annotation>>();
+    private final Map<String, PropertyDescriptorImpl> descriptorMap =
+        new HashMap<String, PropertyDescriptorImpl>();
+    private final Set<ConstraintDescriptorImpl<? extends Annotation>> constraints =
+        new HashSet<ConstraintDescriptorImpl<? extends Annotation>>();
     private boolean isConstrained;
 
     private Builder(Class<T> clazz) {
@@ -55,7 +58,7 @@
     }
 
     public Builder<T> add(
-        ConstraintDescriptor<? extends Annotation> constraintDescriptor) {
+        ConstraintDescriptorImpl<? extends Annotation> constraintDescriptor) {
       constraints.add(constraintDescriptor);
       return this;
     }
@@ -65,8 +68,8 @@
           constraints);
     }
 
-    public Builder<T> put(String key, PropertyDescriptor value) {
-      descriptorMap.put(key, value);
+    public Builder<T> put(String key, PropertyDescriptorImpl value) {
+      descriptorMap.put(key, value.shallowCopy());
       return this;
     }
 
@@ -81,14 +84,16 @@
   }
 
   private final Class<T> clazz;
-  private final Set<ConstraintDescriptor<?>> constraints = new HashSet<ConstraintDescriptor<?>>();
+  private final Set<ConstraintDescriptorImpl<?>> constraints = new HashSet<ConstraintDescriptorImpl<?>>();
 
-  private final Map<String, PropertyDescriptor> descriptorMap = new HashMap<String, PropertyDescriptor>();
+  private final Map<String, PropertyDescriptorImpl> descriptorMap = new HashMap<String, PropertyDescriptorImpl>();
   private final boolean isBeanConstrained;
+  
+  private GroupInheritanceMap groupInheritanceMap;
 
   private GwtBeanDescriptorImpl(Class<T> clazz, boolean isConstrained,
-      Map<String, PropertyDescriptor> descriptorMap,
-      Set<ConstraintDescriptor<?>> constraints) {
+      Map<String, PropertyDescriptorImpl> descriptorMap,
+      Set<ConstraintDescriptorImpl<?>> constraints) {
     super();
     this.clazz = clazz;
     this.isBeanConstrained = isConstrained;
@@ -96,33 +101,53 @@
     this.constraints.addAll(constraints);
   }
 
+  @Override
   public ConstraintFinder findConstraints() {
-    // TODO(nchalko) implement
-    return null;
+    return new ConstraintFinderImpl(groupInheritanceMap, constraints);
   }
 
+  @Override
   public Set<PropertyDescriptor> getConstrainedProperties() {
-    return new HashSet<PropertyDescriptor>(descriptorMap.values());
+    Collection<PropertyDescriptorImpl> props = descriptorMap.values();
+    for (PropertyDescriptorImpl prop : props) {
+      prop.setGroupInheritanceMap(groupInheritanceMap);
+    }
+    return new HashSet<PropertyDescriptor>(props);
   }
 
+  @Override
   public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
     // Copy for safety
     return new HashSet<ConstraintDescriptor<?>>(constraints);
   }
 
+  @Override
   public PropertyDescriptor getConstraintsForProperty(String propertyName) {
-    return descriptorMap.get(propertyName);
+    PropertyDescriptorImpl propDesc = descriptorMap.get(propertyName);
+    if (propDesc != null) {
+      propDesc.setGroupInheritanceMap(groupInheritanceMap);
+    }
+    return propDesc;
   }
 
+  @Override
   public Class<?> getElementClass() {
     return clazz;
   }
 
+  @Override
   public boolean hasConstraints() {
     return !constraints.isEmpty();
   }
 
+  @Override
   public boolean isBeanConstrained() {
     return isBeanConstrained;
   }
+
+  @Override
+  public void setGroupInheritanceMap(GroupInheritanceMap groupInheritanceMap) {
+    // TODO(idol) Find some way to pass this via the constructor rather than after creation
+    this.groupInheritanceMap = groupInheritanceMap;
+  }
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/validation/client/impl/GwtSpecificValidator.java b/user/src/com/google/gwt/validation/client/impl/GwtSpecificValidator.java
index a7737b2..cdc42dd 100644
--- a/user/src/com/google/gwt/validation/client/impl/GwtSpecificValidator.java
+++ b/user/src/com/google/gwt/validation/client/impl/GwtSpecificValidator.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import java.util.Set;
 
 import javax.validation.ConstraintViolation;
@@ -36,14 +38,15 @@
    * object (and associated objects including
    * <code>ConstraintDescriptor<code>s) are immutable.
    *
-   *
+   * @param groupInheritanceMap The group inheritance map for the validator.
    * @return the bean descriptor for the class associated with this validator.
    *
    * @throws IllegalArgumentException if clazz is null
    * @throws ValidationException if a non recoverable error happens during the
    *           metadata discovery or if some constraints are invalid.
    */
-  GwtBeanDescriptor<G> getConstraints() throws ValidationException;
+  GwtBeanDescriptor<G> getConstraints(GroupInheritanceMap groupInheritanceMap)
+      throws ValidationException;
 
   /**
    * Validates all constraints on <code>object</code>.
diff --git a/user/src/com/google/gwt/validation/client/impl/PropertyDescriptorImpl.java b/user/src/com/google/gwt/validation/client/impl/PropertyDescriptorImpl.java
index e70fa04..310be32 100644
--- a/user/src/com/google/gwt/validation/client/impl/PropertyDescriptorImpl.java
+++ b/user/src/com/google/gwt/validation/client/impl/PropertyDescriptorImpl.java
@@ -15,8 +15,9 @@
  */
 package com.google.gwt.validation.client.impl;
 
+import com.google.gwt.validation.client.GroupInheritanceMap;
+
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -31,48 +32,67 @@
 public final class PropertyDescriptorImpl implements PropertyDescriptor {
 
   private boolean cascaded;
-  private Set<ConstraintDescriptor<?>> descriptors = new HashSet<ConstraintDescriptor<?>>();
+  private Set<ConstraintDescriptorImpl<?>> descriptors;
   private Class<?> elementClass;
   private String name;
+  private GroupInheritanceMap groupInheritanceMap;
 
-  /**
-   * @param name
-   * @param elementClass
-   * @param cascaded
-   * @param descriptors
-   */
   public PropertyDescriptorImpl(String name, Class<?> elementClass,
-      boolean cascaded, ConstraintDescriptor<?>... descriptors) {
+      boolean cascaded, ConstraintDescriptorImpl<?>... descriptors) {
+    this(name, elementClass, cascaded, null, descriptors);
+  }
+
+  public PropertyDescriptorImpl(String name, Class<?> elementClass,
+      boolean cascaded, GroupInheritanceMap groupInheritanceMap,
+      ConstraintDescriptorImpl<?>... descriptors) {
     super();
 
     this.elementClass = elementClass;
     this.cascaded = cascaded;
     this.name = name;
-    this.descriptors = new HashSet<ConstraintDescriptor<?>>(
+    this.groupInheritanceMap = groupInheritanceMap;
+    this.descriptors = new HashSet<ConstraintDescriptorImpl<?>>(
         Arrays.asList(descriptors));
   }
 
+  @Override
   public ConstraintFinder findConstraints() {
-    return null;
+    return new ConstraintFinderImpl(groupInheritanceMap, descriptors);
   }
 
+  @Override
   public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
-    return Collections.unmodifiableSet(descriptors);
+    return findConstraints().getConstraintDescriptors();
   }
 
+  @Override
   public Class<?> getElementClass() {
     return elementClass;
   }
 
+  @Override
   public String getPropertyName() {
     return name;
   }
 
+  @Override
   public boolean hasConstraints() {
     return !descriptors.isEmpty();
   }
 
+  @Override
   public boolean isCascaded() {
     return cascaded;
   }
+
+  public void setGroupInheritanceMap(GroupInheritanceMap groupInheritanceMap) {
+    // TODO(idol) Find some way to pass this via the constructor rather than after creation
+    this.groupInheritanceMap = groupInheritanceMap;
+  }
+
+  public PropertyDescriptorImpl shallowCopy() {
+    ConstraintDescriptorImpl<?>[] desc = new ConstraintDescriptorImpl<?>[descriptors.size()];
+    descriptors.toArray(desc);
+    return new PropertyDescriptorImpl(name, elementClass, cascaded, groupInheritanceMap, desc);
+  }
 }
diff --git a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
index a95d9b9..1f349e3 100644
--- a/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/GwtSpecificValidatorCreator.java
@@ -41,6 +41,8 @@
 import com.google.gwt.thirdparty.guava.common.primitives.Primitives;
 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
 import com.google.gwt.user.rebind.SourceWriter;
+import com.google.gwt.validation.client.ConstraintOrigin;
+import com.google.gwt.validation.client.GroupInheritanceMap;
 import com.google.gwt.validation.client.impl.AbstractGwtSpecificValidator;
 import com.google.gwt.validation.client.impl.ConstraintDescriptorImpl;
 import com.google.gwt.validation.client.impl.GwtBeanDescriptor;
@@ -266,6 +268,18 @@
     return ImmutableSet.copyOf(Maps.filterKeys(map, inBest).values());
   }
 
+  private static ConstraintOrigin convertConstraintOriginEnum(
+      org.hibernate.validator.metadata.ConstraintOrigin definedOn) {
+    switch (definedOn) {
+      case DEFINED_IN_HIERARCHY:
+        return ConstraintOrigin.DEFINED_IN_HIERARCHY;
+      case DEFINED_LOCALLY:
+        return ConstraintOrigin.DEFINED_LOCALLY;
+      default:
+        throw new IllegalArgumentException("Unable to convert: unknown ConstraintOrigin value");
+    }
+  }
+
   /**
    * Gets the best {@link ConstraintValidator}.
    *
@@ -331,7 +345,7 @@
   @Override
   protected void compose(ClassSourceFileComposerFactory composerFactory) {
     addImports(composerFactory, Annotation.class, ConstraintViolation.class,
-        GWT.class, GwtBeanDescriptor.class, GwtValidationContext.class,
+        GWT.class, GroupInheritanceMap.class, GwtBeanDescriptor.class, GwtValidationContext.class,
         HashSet.class, IllegalArgumentException.class, Set.class,
         ValidationException.class);
     composerFactory.setSuperclass(AbstractGwtSpecificValidator.class.getCanonicalName()
@@ -489,28 +503,6 @@
     return getAnnotation(p, useField, Valid.class) != null;
   }
 
-  /**
-   * Handles returning an {@link ElementType} for a given property constraint.
-   * In the situation where a property has the same constraint type applied to it twice
-   * (once via a field and once via a method), then {@link ElementType#FIELD} is returned first
-   * and {@link ElementType#METHOD} is returned after. This should be safe because the bean
-   * introspection always returns field annotations before getter annotations.
-   */
-  private ElementType inferElementType(PropertyDescriptor propertyDescriptor,
-      boolean seenBefore) {
-    if (beanHelper.hasField(propertyDescriptor)) {
-      if (beanHelper.hasGetter(propertyDescriptor)) {
-        // this property should be validated twice
-        if (seenBefore) {
-          // the FIELD type has already been returned the first time
-          return ElementType.METHOD;
-        }
-      }
-      return ElementType.FIELD;
-    }
-    return ElementType.METHOD;
-  }
-
   private boolean isPropertyConstrained(BeanHelper helper, PropertyDescriptor p) {
     Set<PropertyDescriptor> propertyDescriptors =
         helper.getBeanDescriptor().getConstrainedProperties();
@@ -622,6 +614,7 @@
   private void writeConstraintDescriptor(SourceWriter sw,
       ConstraintDescriptor<? extends Annotation> constraint,
       ElementType elementType,
+      ConstraintOrigin origin,
       String constraintDescripotorVar) throws UnableToCompleteException {
     Class<? extends Annotation> annotationType =
         constraint.getAnnotation().annotationType();
@@ -630,7 +623,7 @@
     int count = 0;
     for (ConstraintDescriptor<?> composingConstraint :
         constraint.getComposingConstraints()) {
-      writeConstraintDescriptor(sw, composingConstraint, elementType,
+      writeConstraintDescriptor(sw, composingConstraint, elementType, origin,
           constraintDescripotorVar + "_" + count++);
     }
 
@@ -725,6 +718,11 @@
     sw.print(asLiteral(elementType));
     sw.println(")");
 
+    // .setDefinedOn(origin)
+    sw.print(".setDefinedOn(");
+    sw.print(asLiteral(origin));
+    sw.println(")");
+
     // .build();
     sw.println(".build();");
     sw.outdent();
@@ -774,12 +772,12 @@
          beanHelper.getBeanDescriptor().getConstrainedProperties()) {
       int count = 0;
       // Check if the same annotation is applied to the same property twice (getter and field)
-      Set<Object> seen = Sets.newHashSet();
       for (ConstraintDescriptor<?> constraint : p.getConstraintDescriptors()) {
-        writeConstraintDescriptor(sw, constraint,
-            inferElementType(p, seen.contains(constraint.getAnnotation())),
+        org.hibernate.validator.metadata.ConstraintDescriptorImpl<?> constraintHibernate = 
+            (org.hibernate.validator.metadata.ConstraintDescriptorImpl<?>) constraint;
+        writeConstraintDescriptor(sw, constraint, constraintHibernate.getElementType(),
+            convertConstraintOriginEnum(constraintHibernate.getDefinedOn()),
             constraintDescriptorVar(p.getPropertyName(), count++));
-        seen.add(constraint.getAnnotation());
       }
       writePropertyDescriptor(sw, p);
       if (p.isCascaded()) {
@@ -793,7 +791,10 @@
     int count = 0;
     for (ConstraintDescriptor<?> constraint :
         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++));
     }
 
@@ -829,12 +830,15 @@
   }
 
   private void writeGetDescriptor(SourceWriter sw) {
-    // public GwtBeanDescriptor<beanType> getConstraints() {
+    // public GwtBeanDescriptor<beanType> getConstraints(GroupInheritanceMap groupInheritanceMap) {
     sw.print("public ");
     sw.print("GwtBeanDescriptor<" + beanHelper.getTypeCanonicalName() + "> ");
-    sw.println("getConstraints() {");
+    sw.println("getConstraints(GroupInheritanceMap groupInheritanceMap) {");
     sw.indent();
 
+    // beanDescriptor.setGroupInheritanceMap(groupInheritanceMap);
+    sw.println("beanDescriptor.setGroupInheritanceMap(groupInheritanceMap);");
+
     // return beanDescriptor;
     sw.println("return beanDescriptor;");
 
@@ -957,7 +961,7 @@
   private void writePropertyDescriptor(SourceWriter sw, PropertyDescriptor p) {
     // private final PropertyDescriptor myProperty_pd =
     sw.print("private final ");
-    sw.print(PropertyDescriptor.class.getCanonicalName());
+    sw.print(PropertyDescriptorImpl.class.getCanonicalName());
     sw.print(" ");
     sw.print(p.getPropertyName());
     sw.println("_pd =");
diff --git a/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
index d9708c7..d8f4751 100644
--- a/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
@@ -25,15 +25,20 @@
 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
 import com.google.gwt.user.rebind.SourceWriter;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.GroupInheritanceMap;
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 import com.google.gwt.validation.client.impl.GwtBeanDescriptor;
 import com.google.gwt.validation.client.impl.GwtSpecificValidator;
 import com.google.gwt.validation.client.impl.GwtValidationContext;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.validation.ConstraintViolation;
+import javax.validation.groups.Default;
 import javax.validation.metadata.BeanDescriptor;
 
 /**
@@ -72,7 +77,12 @@
        GwtBeanDescriptor.class,
        GwtSpecificValidator.class,
        GwtValidationContext.class,
+       GroupInheritanceMap.class,
        Set.class,
+       HashSet.class,
+       Map.class,
+       HashMap.class,
+       Default.class,
        ConstraintViolation.class,
        BeanDescriptor.class);
     composerFactory.setSuperclass(AbstractGwtValidator.class.getCanonicalName());
@@ -83,6 +93,8 @@
   protected void writeClassBody(SourceWriter sourceWriter) {
     writeConstructor(sourceWriter);
     sourceWriter.println();
+    writeCreateGroupInheritanceMap(sourceWriter);
+    sourceWriter.println();
     writeValidate(sourceWriter);
     sourceWriter.println();
     writeValidateProperty(sourceWriter);
@@ -99,18 +111,8 @@
     sw.println("public " + getSimpleName() + "() {");
     sw.indent();
 
-    // super( <<groups>>);
-    sw.print("super(");
-    boolean first = true;
-    for (Class<?> group : gwtValidation.groups()) {
-      if (!first) {
-        sw.print(", ");
-      } else {
-        first = false;
-      }
-      sw.print(group.getCanonicalName() + ".class");
-    }
-    sw.println(");");
+    // super(createGroupInheritanceMap());
+    sw.println("super(createGroupInheritanceMap());");
 
     sw.outdent();
     sw.println("}");
@@ -132,9 +134,9 @@
     // object,
     sw.println(objectName + ", ");
 
-    // MyBeanValidator.INSTANCE.getConstraints(),
+    // MyBeanValidator.INSTANCE.getConstraints(getGroupInheritanceMap()),
     sw.print(bean.getFullyQualifiedValidatorName());
-    sw.println(".INSTANCE.getConstraints(), ");
+    sw.println(".INSTANCE.getConstraints(getGroupInheritanceMap()), ");
 
     // getMessageInterpolator(),
     sw.println("getMessageInterpolator(), ");
@@ -145,6 +147,39 @@
     sw.outdent();
   }
 
+  private void writeCreateGroupInheritanceMap(SourceWriter sw) {
+    // private static GroupInheritanceMap creategroupInheritanceMap() {
+    sw.println("private static GroupInheritanceMap createGroupInheritanceMap() {");
+    sw.indent();
+    
+    // GroupInheritanceMap groupInheritanceMap = GroupInheritanceMap.builder()
+    sw.println("return GroupInheritanceMap.builder()");
+    sw.indent();
+    sw.indent();
+    for (Class<?> group : gwtValidation.groups()) {
+      // .addGroup(<<group>>
+      sw.print(".addGroup(");
+      sw.print(group.getCanonicalName() + ".class");
+      Class<?>[] parentInterfaces = group.getInterfaces();
+      for (Class<?> parent : parentInterfaces) {
+        // , <<parent class>>
+        sw.print(", ");
+        sw.print(parent.getCanonicalName() + ".class");
+      }
+      // )
+      sw.println(")");
+    }
+
+    // .build();
+    sw.println(".build();");
+    sw.outdent();
+    sw.outdent();
+
+    // }
+    sw.outdent();
+    sw.println("}");
+  }
+
   private void writeGetConstraintsForClass(SourceWriter sw) {
     // public BeanDescriptor getConstraintsForClass(Class<?> clazz {
     sw.println("public BeanDescriptor getConstraintsForClass(Class<?> clazz) {");
@@ -170,10 +205,10 @@
     sw.println("if (clazz.equals(" + bean.getTypeCanonicalName() + ".class)) {");
     sw.indent();
 
-    // return MyBeanValidator.INSTANCE.getConstraints();
+    // return MyBeanValidator.INSTANCE.getConstraints(getGroupInheritanceMap());
     sw.print("return ");
     sw.print(bean.getFullyQualifiedValidatorName());
-    sw.println(".INSTANCE.getConstraints();");
+    sw.println(".INSTANCE.getConstraints(getGroupInheritanceMap());");
 
     // }
     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 7e93219..41e97c7 100644
--- a/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java
+++ b/user/src/com/google/gwt/validation/rebind/ValidatorGenerator.java
@@ -62,6 +62,13 @@
       throw new UnableToCompleteException();
     }
 
+    if (gwtValidation.groups().length == 0) {
+      logger.log(TreeLogger.ERROR,
+          "The @" + GwtValidation.class.getSimpleName() + "  of " + typeName
+              + "must specify at least one validation group.", null);
+      throw new UnableToCompleteException();
+    }
+
     TreeLogger validatorLogger = logger.branch(TreeLogger.DEBUG,
         "Generating Validator for  '" + validatorType.getQualifiedSourceName()
             + "'", null);
diff --git a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
index 0382f40..210a562 100644
--- a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
+++ b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.emultest.java.util;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.junit.client.GWTTestCase;
 
 import java.util.List;
@@ -44,4 +45,8 @@
   public String getModuleName() {
     return "com.google.gwt.emultest.EmulSuite";
   }
+
+  protected boolean isJdk7() {
+    return !GWT.isScript() && System.getProperty("java.version", "none").startsWith("1.7.");
+  }
 }
diff --git a/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
index 2a0b5bd..30ea28e 100644
--- a/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
@@ -327,19 +327,14 @@
    * @see java.util.TreeMap#TreeMap(Map)
    */
   @SuppressWarnings("unchecked")
-  public void testConstructor_Map_throwsClassCastException() {
-    Map sourceMap = createMap();
+  public void testConstructor_Map_rawType() {
+    Map sourceMap = new HashMap();
     sourceMap.put(getConflictingKey(), getConflictingValue());
+    // In Java, raw types can be used to defeat type checking.
+    // For TreeMap, this works if the key is Comparable and there's
+    // only one entry in the map. If there's more than one entry,
+    // the compare() method will be called and that might throw.
     new TreeMap<K, V>(sourceMap);
-
-    // This does not fail as might be expected.
-    // TODO I don't know of any case where this could happen.
-    // try {
-    // new TreeMap<K, V>(sourceMap);
-    // fail("expected exception");
-    // } catch (ClassCastException e) {
-    // // expected outcome
-    // }
   }
 
   /**
@@ -1062,18 +1057,18 @@
 
   /**
    * Test method for 'java.util.Map.put(Object, Object)'. This test shows some
-   * bad behavior of the TreeMap class. A mapping with null key can be put in
-   * but several methods are are unusable afterward.
+   * bad behavior of the TreeMap class before JDK 7. A mapping with null key can
+   * be put in but several methods are are unusable afterward.
    * 
    * A SortedMap with natural ordering (no comparator) is supposed to throw a
    * null pointer exception if a null keys are "not supported". For a natural
-   * ordered TreeMap, a null pointer exception is not thrown. But, the map is
-   * left in a state where any other key based methods result in a null pointer
-   * exception.
+   * ordered TreeMap before JDK 7, a null pointer exception is not thrown. But,
+   * the map is left in a state where any other key based methods result in a
+   * null pointer exception.
    * 
    * @see java.util.Map#put(Object, Object)
    */
-  public void testPut_nullKey_poison() {
+  public void testPut_nullKey() {
     SortedMap<K, V> sortedMap = createSortedMap();
 
     if (useNullKey()) {
@@ -1099,7 +1094,42 @@
       sortedMap.subMap(getLessThanMinimumKey(), getGreaterThanMaximumKey());
       sortedMap.headMap(getLessThanMinimumKey());
       sortedMap.tailMap(getLessThanMinimumKey());
+    } else if (isJdk7()) {
+      // nulls are rejected immediately and don't poison the map anymore
+      try {
+        assertNull(sortedMap.put(null, getValues()[0]));
+        fail("should have thrown");
+      } catch (NullPointerException e) {
+        // expected outcome
+      }
+      try {
+        assertNull(sortedMap.put(null, getValues()[1]));
+        fail("expected exception adding second null");
+      } catch (NullPointerException e) {
+        // expected outcome
+      }
+      try {
+        sortedMap.containsKey(null);
+        fail("expected exception on containsKey(null)");
+      } catch (NullPointerException e) {
+        // expected outcome
+      }
+      sortedMap.containsKey(getKeys()[0]);
+      try {
+        sortedMap.get(null);
+        fail("expected exception on get(null)");
+      } catch (NullPointerException e) {
+        // expected outcome
+      }
+      sortedMap.get(getKeys()[0]);
+      try {
+        sortedMap.remove(null);
+      } catch (NullPointerException e) {
+        // expected
+      }
+      sortedMap.remove(getKeys()[0]);
     } else {
+      // before JDK 7, nulls poisoned the map
       try {
         assertNull(sortedMap.put(null, getValues()[0]));
         // note: first null added is not required to throw NPE since no
@@ -1395,12 +1425,14 @@
     // The _throwsUnsupportedOperationException version of this test will
     // verify that the method is not supported.
     if (isPutAllSupported) {
-      Map sourceMap = createMap();
+      Map sourceMap = new HashMap();
       sourceMap.put(getConflictingKey(), getConflictingValue());
 
       Map<K, V> destMap = createMap();
       destMap.put(getKeys()[0], getValues()[0]);
       try {
+        // This throws in dev mode because we're putting a second
+        // entry in the map and the TreeMap calls the compare method.
         destMap.putAll(sourceMap);
         assertTrue("CCE expected in Development Mode", GWT.isScript());
       } catch (ClassCastException e) {
diff --git a/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java b/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java
index 75502cd..29a84e7 100644
--- a/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java
@@ -339,12 +339,14 @@
     // The _throwsUnsupportedOperationException version of this test will
     // verify that the method is not supported.
     if (isPutAllSupported) {
-      Set sourceSet = createSet();
+      Set sourceSet = new HashSet();
       sourceSet.add(getConflictingKey());
 
       Set<E> destSet = createSet();
       destSet.add(getKeys()[0]);
       try {
+        // This throws in dev mode because we're putting a second entry in
+        // the set and TreeSet calls the compare method to order them.
         destSet.addAll(sourceSet);
         assertTrue("CCE expected in Development Mode", GWT.isScript());
       } catch (ClassCastException e) {
@@ -490,19 +492,13 @@
    * @see java.util.TreeSet#TreeSet(Set)
    */
   @SuppressWarnings("unchecked")
-  public void testConstructor_Set_throwsClassCastException() {
-    Set sourceSet = createSet();
+  public void testConstructor_Set_rawType() {
+    Set sourceSet = new HashSet();
     sourceSet.add(getConflictingKey());
+    // Raw types can be used to defeat the type system, and this will work
+    // so long as the key is Comparable and there's only one entry (so compare()
+    // won't be called.)
     new TreeSet<E>(sourceSet);
-
-    // This does not fail as might be expected.
-    // TODO I don't know of any case where this could happen.
-    // try {
-    // new TreeSet<E, V>(sourceMap);
-    // fail("expected exception");
-    // } catch (ClassCastException e) {
-    // // expected outcome
-    // }
   }
 
   /**
diff --git a/user/test/com/google/gwt/resources/client/CSSResourceTest.java b/user/test/com/google/gwt/resources/client/CSSResourceTest.java
index 87d0517..ab91748 100644
--- a/user/test/com/google/gwt/resources/client/CSSResourceTest.java
+++ b/user/test/com/google/gwt/resources/client/CSSResourceTest.java
@@ -319,6 +319,11 @@
 
     // Check @def substitution
     assertTrue(text.contains("50px"));
+    // Check @def substitution into function arguments
+    // Note that GWT transforms rgb(R, G, B) into #rrggbb form.
+    assertTrue(text.contains("-moz-linear-gradient(left, #007f00, #00007f 50%);"));
+    assertTrue(text.contains("-webkit-linear-gradient(left, #007f00, #00007f 50%);"));
+    assertTrue(text.contains("linear-gradient(to right, #007f00, #00007f 50%);"));
 
     // Check merging semantics
     assertTrue(text.indexOf("static:PASSED") < text.indexOf("runtime:PASSED"));
@@ -334,7 +339,7 @@
         + css.mayNotCombine2()));
 
     // Check commonly-used CSS3 constructs
-    assertTrue(text.contains("background-color:rgba(0,0,0,0.5);"));
+    assertTrue(text.contains("background-color:rgba(0, 0, 0, 0.5);"));
 
     // Check external references
     assertEquals("externalA", css.externalA());
@@ -368,7 +373,7 @@
     assertFalse("10px".equals(defines.overrideIntClass()));
     assertFalse("10".equals(defines.overrideIntClass()));
 
-    assertEquals("1px solid rgba(0,0,0,0.2)", defines.multiValueBorderDef());
+    assertEquals("1px solid rgba(0, 0, 0, 0.2)", defines.multiValueBorderDef());
   }
 
   public void testEnsureInjected() {
diff --git a/user/test/com/google/gwt/resources/client/test.css b/user/test/com/google/gwt/resources/client/test.css
index bfc2b2c..6317916 100644
--- a/user/test/com/google/gwt/resources/client/test.css
+++ b/user/test/com/google/gwt/resources/client/test.css
@@ -63,6 +63,16 @@
     content: 'bar';
 }
 
+@def GREEN #007f00;
+@def BLUE_AT_50PCT rgb(0, 0, 127) 50%;
+@def TO_RIGHT_GREEN_TO_BLUE_50PCT to right, GREEN, BLUE_AT_50PCT;
+@external testSubstitutionsInFunctions;
+.testSubstitutionsInFunctions {
+  background-image: -moz-linear-gradient(left, #007f00, rgb(0, 0, 127) 50%);
+  background-image: -webkit-linear-gradient(left, GREEN, BLUE_AT_50PCT);
+  background-image: linear-gradient(TO_RIGHT_GREEN_TO_BLUE_50PCT);
+}
+
 /* Test structural modifications */
 @if (false) {
   div {
diff --git a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
index 803d95d..434e209 100644
--- a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
@@ -107,6 +107,7 @@
     });
     RootPanel.get().add(rta);
     rta.setFocus(true);
+    RootPanel.get().remove(rta);
 
     // Webkit based browsers will not fire a focus event if the browser window
     // is behind another window, so we can only test that this doesn't cause
diff --git a/user/test/com/google/gwt/validation/ValidationClientJreSuite.java b/user/test/com/google/gwt/validation/ValidationClientJreSuite.java
index bc794e7..7d17aa8 100644
--- a/user/test/com/google/gwt/validation/ValidationClientJreSuite.java
+++ b/user/test/com/google/gwt/validation/ValidationClientJreSuite.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.validation;
 
+import com.google.gwt.validation.client.GroupInheritanceMapTest;
 import com.google.gwt.validation.client.impl.NodeImplTest;
 import com.google.gwt.validation.client.impl.PathImplTest;
 
@@ -31,6 +32,7 @@
         "Test suite for validation client code that does not require GWT.");
     suite.addTestSuite(PathImplTest.class);
     suite.addTestSuite(NodeImplTest.class);
+    suite.addTestSuite(GroupInheritanceMapTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/validation/client/GroupInheritanceMapTest.java b/user/test/com/google/gwt/validation/client/GroupInheritanceMapTest.java
new file mode 100644
index 0000000..a582a93
--- /dev/null
+++ b/user/test/com/google/gwt/validation/client/GroupInheritanceMapTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.client;
+
+import junit.framework.TestCase;
+
+import java.util.Set;
+import java.util.HashSet;
+
+import javax.validation.groups.Default;
+
+/**
+ * Test case for {@link GroupInheritanceMap}.
+ */
+public class GroupInheritanceMapTest extends TestCase {
+
+  private GroupInheritanceMap createWithTestGroups() {
+    return GroupInheritanceMap.builder()
+        .addGroup(Part1.class, MiniPart.class)
+        .addGroup(Part2.class)
+        .addGroup(Big.class, Part1.class, Part2.class)
+        .addGroup(MiniPart.class, SuperSmall.class)
+        .addGroup(SuperSmall.class)
+        .build();
+  }
+
+  public void testDefaultGroupExists() {
+    assertTrue(GroupInheritanceMap.builder().build().containsGroup(Default.class));
+  }
+  
+  public void testFindAllExtendedGroups() {
+    // should get all of the groups and all of their parents recursively
+    GroupInheritanceMap groupInheritanceMap = createWithTestGroups();
+    Set<Class<?>> baseGroups = new HashSet<Class<?>>();
+    baseGroups.add(Part1.class);
+    baseGroups.add(Part2.class);
+    Set<Class<?>> desired = new HashSet<Class<?>>();
+    desired.add(Part1.class);
+    desired.add(Part2.class);
+    desired.add(MiniPart.class);
+    desired.add(SuperSmall.class);
+    assertEquals(desired, groupInheritanceMap.findAllExtendedGroups(baseGroups));
+  }
+
+  public void testFindingExtendedGroupsThrowsExceptionWhenUnknown() {
+    // should throw exception when the group has not been added to the map
+    GroupInheritanceMap groupInheritanceMap = GroupInheritanceMap.builder().build();
+    assertFalse(groupInheritanceMap.containsGroup(MiniPart.class));
+    try {
+      Set<Class<?>> miniPart = new HashSet<Class<?>>();
+      miniPart.add(MiniPart.class);
+      groupInheritanceMap.findAllExtendedGroups(miniPart);
+      fail("Expected an " + IllegalArgumentException.class);
+    } catch (IllegalArgumentException expected) {
+      // expected
+    }
+  }
+
+  public void testGetAllGroups() {
+    // should return all groups and their parents recursively
+    GroupInheritanceMap groupInheritanceMap = createWithTestGroups();
+    Set<Class<?>> desired = new HashSet<Class<?>>();
+    desired.add(Default.class);
+    desired.add(Part1.class);
+    desired.add(Part2.class);
+    desired.add(MiniPart.class);
+    desired.add(SuperSmall.class);
+    desired.add(Big.class);
+    assertEquals(desired, groupInheritanceMap.getAllGroups());
+  }
+
+  private interface Part1 extends MiniPart {
+  }
+  
+  private interface MiniPart extends SuperSmall {
+  }
+  
+  private interface SuperSmall {
+  }
+  
+  private interface Part2 {
+  }
+  
+  private interface Big extends Part1, Part2 {
+  }
+}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/application/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/application/TckTestValidatorFactory.java
index 2916689..1dc3ea6 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/application/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/application/TckTestValidatorFactory.java
@@ -21,6 +21,7 @@
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -31,7 +32,8 @@
    * Marker Interface for {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
-      Building.class, SuperWoman.class, Visibility.class, Woman.class})
+      Building.class, SuperWoman.class, Visibility.class, Woman.class},
+      groups = {Default.class, TightSecurity.class, DummyGroup.class})
   public static interface GwtValidator extends Validator {
   }
 
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 8a3c42a..36f9864 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
@@ -59,7 +59,6 @@
     delegate.testImplicitGrouping();
   }
 
-  @Failing(issue = 5801)
   public void testValidateAgainstDifferentGroups() {
     delegate.testValidateAgainstDifferentGroups();
   }
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 aae5a96..9db324a 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
@@ -21,6 +21,7 @@
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -32,7 +33,10 @@
    */
   @GwtValidation(value = {
       Address.class, Animal.class, Book.class, Car.class, Order.class,
-      User.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})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequence/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequence/TckTestValidatorFactory.java
index 98587ac..857aa88 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequence/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/groupsequence/TckTestValidatorFactory.java
@@ -20,9 +20,17 @@
 import com.google.gwt.validation.client.GwtValidation;
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.All;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.AllReverse;
 import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.Car;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.First;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.InvalidGroupSequence;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.Mixed;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.Second;
+import org.hibernate.jsr303.tck.tests.constraints.groups.groupsequence.SequenceResolutionTest.Third;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -32,7 +40,9 @@
   /**
    * Marker Interface to {@link GWT#create(Class)}.
    */
-  @GwtValidation(value = {Car.class, TestEntity.class})
+  @GwtValidation(value = {Car.class, TestEntity.class},
+      groups = {Default.class, InvalidGroupSequence.class, First.class, Second.class, Third.class,
+        All.class, AllReverse.class, Mixed.class, Complete.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/GroupInheritanceGwtTest.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/GroupInheritanceGwtTest.java
index 09f3068..ca4c15b 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/GroupInheritanceGwtTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/GroupInheritanceGwtTest.java
@@ -17,37 +17,29 @@
 
 import com.google.gwt.junit.client.GWTTestCase;
 
-import org.hibernate.jsr303.tck.util.client.Failing;
 import org.hibernate.jsr303.tck.util.client.NonTckTest;
 
 /**
  * Test wrapper for {@link GroupInheritanceTest}.
  */
 public class GroupInheritanceGwtTest extends GWTTestCase {
-  // TODO(nchalko) causes com.google.gwt.dev.jjs.InternalCompilerException:
-  // see http://code.google.com/p/google-web-toolkit/issues/detail?id=6508
-  // private final GroupInheritanceTest delegate = new GroupInheritanceTest();
+  private final GroupInheritanceTest delegate = new GroupInheritanceTest();
 
   @Override
   public String getModuleName() {
     return "org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.TckTest";
   }
 
-
   @NonTckTest
   public void testDummy() {
     // There must be at least one passing test.
   }
 
-  @Failing(issue = 5801)
   public void testGroupCanInheritGroupsViaInterfaceInheritance() {
-    // delegate.testGroupCanInheritGroupsViaInterfaceInheritance();
-    fail("See http://code.google.com/p/google-web-toolkit/issues/detail?id=6508");
+    delegate.testGroupCanInheritGroupsViaInterfaceInheritance();
   }
 
-  @Failing(issue = 5801)
   public void testGroupMembership() {
-    // delegate.testGroupMembership();
-    fail("See http://code.google.com/p/google-web-toolkit/issues/detail?id=6508");
+    delegate.testGroupMembership();
   }
 }
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/TckTestValidatorFactory.java
index 0e045de..9464ace 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/groups/inheritance/TckTestValidatorFactory.java
@@ -20,10 +20,14 @@
 import com.google.gwt.validation.client.GwtValidation;
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
+import org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.GroupInheritanceTest.All;
 import org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.GroupInheritanceTest.MiniaturePart;
 import org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.GroupInheritanceTest.Part;
+import org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.GroupInheritanceTest.PostManufacturing;
+import org.hibernate.jsr303.tck.tests.constraints.groups.inheritance.GroupInheritanceTest.PreManufacturing;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -33,7 +37,8 @@
   /**
    * Marker Interface to {@link GWT#create(Class)}.
    */
-  @GwtValidation(value = {MiniaturePart.class, Part.class})
+  @GwtValidation(value = {MiniaturePart.class, Part.class},
+      groups = {Default.class, All.class, PreManufacturing.class, PostManufacturing.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/metadata/ElementDescriptorGwtTest.java b/user/test/org/hibernate/jsr303/tck/tests/metadata/ElementDescriptorGwtTest.java
index 63fffe1..8d2622b 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/metadata/ElementDescriptorGwtTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/metadata/ElementDescriptorGwtTest.java
@@ -30,7 +30,6 @@
     return "org.hibernate.jsr303.tck.tests.metadata.TckTest";
   }
 
-  @Failing(issue = 5932)
   public void testDeclaredOn() {
     delegate.testDeclaredOn();
   }
@@ -47,7 +46,6 @@
     delegate.testHasConstraints();
   }
 
-  @Failing(issue = 5932)
   public void testLookingAt() {
     delegate.testLookingAt();
   }
@@ -62,7 +60,6 @@
     delegate.testUnorderedAndMatchingGroupsWithDefaultGroupOverriding();
   }
 
-  @Failing(issue = 5932)
   public void testUnorderedAndMatchingGroupsWithInheritance() {
     delegate.testUnorderedAndMatchingGroupsWithInheritance();
   }
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 a6fbc25..a32aaf5 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/metadata/TckTestValidatorFactory.java
@@ -21,6 +21,7 @@
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * Test {@link AbstractGwtValidatorFactory} for
@@ -31,8 +32,10 @@
    * Marker Interface to {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
-      Account.class, Customer.class, Man.class, Order.class, Person.class,
-      SubClass.class, SuperClass.class, UnconstraintEntity.class})
+        Account.class, Customer.class, Man.class, Order.class, Person.class,
+        SubClass.class, SuperClass.class, UnconstraintEntity.class},
+      groups = {Default.class, SuperClass.BasicGroup.class, SuperClass.InheritedGroup.class,
+        SuperClass.UnusedGroup.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/validation/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/validation/TckTestValidatorFactory.java
index 12cb1b7..550e01c 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/validation/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/validation/TckTestValidatorFactory.java
@@ -23,8 +23,11 @@
 import org.hibernate.jsr303.tck.tests.validation.PropertyPathTest.ActorDB;
 import org.hibernate.jsr303.tck.tests.validation.PropertyPathTest.VerySpecialClass;
 import org.hibernate.jsr303.tck.tests.validation.ValidateTest.Car;
+import org.hibernate.jsr303.tck.tests.validation.ValidateTest.First;
+import org.hibernate.jsr303.tck.tests.validation.ValidateTest.Second;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -35,9 +38,10 @@
    * Marker Interface for {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
-      ActorArrayBased.class, ActorDB.class, ActorListBased.class, Actor.class,
-      Address.class, BadlyBehavedEntity.class, Car.class, Customer.class,
-      Engine.class, Order.class, VerySpecialClass.class})
+        ActorArrayBased.class, ActorDB.class, ActorListBased.class, Actor.class,
+        Address.class, BadlyBehavedEntity.class, Car.class, Customer.class,
+        Engine.class, Order.class, VerySpecialClass.class},
+      groups = {Default.class, First.class, Second.class, Last.class, Address.Minimal.class})
   public static interface GwtValidator extends Validator {
   }
 
diff --git a/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/TckTestValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/TckTestValidatorFactory.java
index 1dafc04..8938936 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/TckTestValidatorFactory.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/validation/graphnavigation/TckTestValidatorFactory.java
@@ -21,6 +21,7 @@
 import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import javax.validation.Validator;
+import javax.validation.groups.Default;
 
 /**
  * {@link AbstractGwtValidatorFactory} implementation that uses
@@ -31,9 +32,10 @@
    * Marker Interface for {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
-      AnimalCaretaker.class, Condor.class, Elephant.class, GameReserve.class,
-      MultiCage.class, MultiCage.class, Order.class, Parent.class,
-      SingleCage.class, User.class, Zebra.class, Zoo.class})
+        AnimalCaretaker.class, Condor.class, Elephant.class, GameReserve.class,
+        MultiCage.class, MultiCage.class, Order.class, Parent.class,
+        SingleCage.class, User.class, Zebra.class, Zoo.class},
+      groups = {Default.class, Parent.ProperOrder.class})
   public static interface GwtValidator extends Validator {
   }