Basic MessageIntrpolation.
Refactored the bootstrap to hook via ValidatorFactory
[JSR 303 TCK Result] 47 of 258 (18.22%) Pass with 17 Failures and 14 Errors.
Review at http://gwt-code-reviews.appspot.com/1230801

Review by: rchandia@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9469 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/common.ant.xml b/samples/common.ant.xml
index 5de8f54..45fe20b 100755
--- a/samples/common.ant.xml
+++ b/samples/common.ant.xml
@@ -157,6 +157,7 @@
     <gwt.checkstyle outputdirectory="${sample.build}">
       <fileset dir="src" >
         <exclude name="org/**/super/org/**/*.java"/>
+        <exclude name="com/google/gwt/sample/validation*/**/ValidationMessages.java" />
       </fileset>
     </gwt.checkstyle>
   </target>
diff --git a/samples/validation/src/com/google/gwt/sample/validation/Validation.gwt.xml b/samples/validation/src/com/google/gwt/sample/validation/Validation.gwt.xml
index b4dbbea..23173e9 100644
--- a/samples/validation/src/com/google/gwt/sample/validation/Validation.gwt.xml
+++ b/samples/validation/src/com/google/gwt/sample/validation/Validation.gwt.xml
@@ -24,8 +24,18 @@
   <source path='shared' />
   <super-source path="super" />
 
+  <!-- Specify the Validator for the Validation bootstrap to use. -->
   <replace-with
-    class="com.google.gwt.sample.validation.client.SampleValidator">
-    <when-type-is class="javax.validation.Validator" />
+    class="com.google.gwt.sample.validation.client.SampleValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory" />
+  </replace-with>
+  
+  <!-- TODO(nchalko) figure out how to make this a attribute of the GwtValidation
+       annotation -->
+  <!--  specify the ValidationMessageResolver to use for your custom validation messages -->
+  <replace-with
+    class="com.google.gwt.sample.validation.client.CustomValidationMessagesResolver">
+    <when-type-is
+      class="com.google.gwt.validation.client.UserValidationMessagesResolver" />
   </replace-with>
 </module>
diff --git a/samples/validation/src/com/google/gwt/sample/validation/client/CustomValidationMessagesResolver.java b/samples/validation/src/com/google/gwt/sample/validation/client/CustomValidationMessagesResolver.java
new file mode 100644
index 0000000..b81c63d
--- /dev/null
+++ b/samples/validation/src/com/google/gwt/sample/validation/client/CustomValidationMessagesResolver.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validation.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.ConstantsWithLookup;
+import com.google.gwt.validation.client.AbstractValidationMessageResolver;
+import com.google.gwt.validation.client.UserValidationMessagesResolver;
+
+/**
+ * {@link UserValidationMessageResolver} that uses the
+ * {@link ValidationMessages}.
+ */
+public class CustomValidationMessagesResolver extends AbstractValidationMessageResolver
+    implements UserValidationMessagesResolver {
+
+  // TODO(nchalko) implement this as part of the GWtValidation annotation
+  // instead of a separate class.
+  protected CustomValidationMessagesResolver() {
+    super((ConstantsWithLookup) GWT.create(ValidationMessages.class));
+  }
+}
\ No newline at end of file
diff --git a/samples/validation/src/com/google/gwt/sample/validation/client/SampleValidator.java b/samples/validation/src/com/google/gwt/sample/validation/client/SampleValidatorFactory.java
similarity index 75%
rename from samples/validation/src/com/google/gwt/sample/validation/client/SampleValidator.java
rename to samples/validation/src/com/google/gwt/sample/validation/client/SampleValidatorFactory.java
index 2050d44..fd5ae12 100644
--- a/samples/validation/src/com/google/gwt/sample/validation/client/SampleValidator.java
+++ b/samples/validation/src/com/google/gwt/sample/validation/client/SampleValidatorFactory.java
@@ -18,17 +18,17 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.sample.validation.shared.ClientGroup;
 import com.google.gwt.sample.validation.shared.Person;
-import com.google.gwt.validation.client.AbstractValidator;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import javax.validation.Validator;
 import javax.validation.groups.Default;
 
 /**
- * {@link Validator} implementation that uses
- * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
+ * {@link AbstractGwtValidatorFactory} that creates the specified {@link GwtValidator}.
  */
-public class SampleValidator extends AbstractValidator {
+public final class SampleValidatorFactory extends AbstractGwtValidatorFactory {
 
   /**
    * Validator marker for the Validation Sample project. Only the classes listed
@@ -39,7 +39,8 @@
   public interface GwtValidator extends Validator {
   }
 
-  public SampleValidator() {
-    super((Validator) GWT.create(SampleValidator.GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.java b/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.java
new file mode 100644
index 0000000..ae526ff
--- /dev/null
+++ b/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validation.client;
+
+/**
+ * Custom validation messages. Interface to represent the constants contained in
+ * resource bundle:
+ * 'com/google/gwt/sample/validation/client/ValidationMessages.properties'
+ * TODO(nchalko) move this to the root package so client and server can share
+ * the same properties files.
+ */
+public interface ValidationMessages extends
+    com.google.gwt.i18n.client.ConstantsWithLookup {
+
+  /**
+   * Translated "Name must be at least {size} characters long.".
+   *
+   * @return translated "Name must be at least {min} characters long."
+   */
+  @DefaultStringValue("Name must be at least {min} characters long.")
+  @Key("custom.name.size.message")
+  String custom_name_size_message();
+}
diff --git a/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.properties b/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.properties
new file mode 100644
index 0000000..a9ea8f1
--- /dev/null
+++ b/samples/validation/src/com/google/gwt/sample/validation/client/ValidationMessages.properties
@@ -0,0 +1,2 @@
+# Put custom messages here.
+custom.name.size.message=Name must be at least {min} characters long.
diff --git a/samples/validation/src/com/google/gwt/sample/validation/shared/Person.java b/samples/validation/src/com/google/gwt/sample/validation/shared/Person.java
index 867dcf8..607bb11 100644
--- a/samples/validation/src/com/google/gwt/sample/validation/shared/Person.java
+++ b/samples/validation/src/com/google/gwt/sample/validation/shared/Person.java
@@ -32,7 +32,7 @@
   private Address address;
 
   @NotNull
-  @Size(min = 4)
+  @Size(min = 4, message = "{custom.name.size.message}")
   private String name;
 
   private long ssn;
diff --git a/samples/validation/src/log4j.properties b/samples/validation/src/log4j.properties
new file mode 100644
index 0000000..bf638d2
--- /dev/null
+++ b/samples/validation/src/log4j.properties
@@ -0,0 +1,5 @@
+#log4j configuration, needed by hibernate validator.
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
\ No newline at end of file
diff --git a/samples/validationtck/src/log4j.properties b/samples/validationtck/src/log4j.properties
new file mode 100644
index 0000000..bf638d2
--- /dev/null
+++ b/samples/validationtck/src/log4j.properties
@@ -0,0 +1,5 @@
+#log4j configuration, needed by hibernate validator.
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
\ No newline at end of file
diff --git a/samples/validationtck/src/org/hibernate/jsr303/tck/super/org/hibernate/jsr303/tck/tests/messageinterpolation/MessageInterpolationTest.java b/samples/validationtck/src/org/hibernate/jsr303/tck/super/org/hibernate/jsr303/tck/tests/messageinterpolation/MessageInterpolationTest.java
new file mode 100644
index 0000000..2f753d6
--- /dev/null
+++ b/samples/validationtck/src/org/hibernate/jsr303/tck/super/org/hibernate/jsr303/tck/tests/messageinterpolation/MessageInterpolationTest.java
@@ -0,0 +1,299 @@
+// $Id: MessageInterpolationTest.java 17620 2009-10-04 19:19:28Z hardy.ferentschik $
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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 org.hibernate.jsr303.tck.tests.messageinterpolation;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import java.util.Set;
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
+import javax.validation.Validator;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Past;
+import javax.validation.constraints.Size;
+import javax.validation.metadata.ConstraintDescriptor;
+
+import org.jboss.test.audit.annotations.SpecAssertion;
+import org.jboss.test.audit.annotations.SpecAssertions;
+import org.jboss.testharness.AbstractTest;
+import org.jboss.testharness.impl.packaging.Artifact;
+import org.jboss.testharness.impl.packaging.ArtifactType;
+import org.jboss.testharness.impl.packaging.Classes;
+import org.jboss.testharness.impl.packaging.IntegrationTest;
+import org.jboss.testharness.impl.packaging.Resource;
+import org.jboss.testharness.impl.packaging.Resources;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import org.testng.annotations.Test;
+
+import org.hibernate.jsr303.tck.util.TestUtil;
+import static org.hibernate.jsr303.tck.util.TestUtil.assertCorrectConstraintViolationMessages;
+import static org.hibernate.jsr303.tck.util.TestUtil.assertCorrectNumberOfViolations;
+import static org.hibernate.jsr303.tck.util.TestUtil.getDefaultMessageInterpolator;
+import static org.hibernate.jsr303.tck.util.TestUtil.getValidatorUnderTest;
+
+/**
+ * Modified by Google:
+ * <ul>
+ * <li>Changed Local to GwtLocale</li>
+ * </ul>
+ * @author Hardy Ferentschik
+ */
+@Artifact(artifactType = ArtifactType.JSR303)
+@Classes({ TestUtil.class, TestUtil.PathImpl.class, TestUtil.NodeImpl.class })
+@Resources({
+    @Resource(source = "ValidationMessages.properties",
+        destination = "WEB-INF/classes/ValidationMessages.properties"),
+    @Resource(source = "ValidationMessages_de.properties",
+        destination = "WEB-INF/classes/ValidationMessages_de.properties")
+})
+@IntegrationTest
+public class MessageInterpolationTest extends AbstractTest {
+
+  @Test
+  @SpecAssertion(section = "4.3.1", id = "a")
+  public void testDefaultMessageInterpolatorIsNotNull() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    assertNotNull( interpolator, "Each bean validation provider must provide a default message interpolator." );
+  }
+
+  @Test
+  @SpecAssertions({
+      @SpecAssertion(section = "4.3.1", id = "e"),
+      @SpecAssertion(section = "4.3.1.1", id = "a")
+  })
+  public void testSuccessfulInterpolationOfValidationMessagesValue() {
+
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "replacement worked";
+    String actual = interpolator.interpolate( "{foo}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "replacement worked replacement worked";
+    actual = interpolator.interpolate( "{foo} {foo}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "This replacement worked just fine";
+    actual = interpolator.interpolate( "This {foo} just fine", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "{} replacement worked {unknown}";
+    actual = interpolator.interpolate( "{} {foo} {unknown}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "b")
+  public void testRecursiveMessageInterpolation() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "fubar" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "recursion worked";
+    String actual = interpolator.interpolate( ( String ) descriptor.getAttributes().get( "message" ), context );
+    assertEquals(
+        expected, actual, "Expansion should be recursive"
+    );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1", id = "d")
+  public void testMessagesCanBeOverriddenAtConstraintLevel() {
+    Validator validator = TestUtil.getValidatorUnderTest();
+    Set<ConstraintViolation<DummyEntity>> constraintViolations = validator.validateProperty(
+        new DummyEntity(), "snafu"
+    );
+    assertCorrectNumberOfViolations( constraintViolations, 1 );
+    assertCorrectConstraintViolationMessages(
+        constraintViolations, "messages can also be overridden at constraint declaration."
+    );
+  }
+
+
+  @Test
+  @SpecAssertions({
+      @SpecAssertion(section = "4.3.1", id = "f"),
+      @SpecAssertion(section = "4.3.1", id = "g"),
+      @SpecAssertion(section = "4.3.1", id = "h")
+  })
+  public void testLiteralCurlyBraces() {
+
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "{";
+    String actual = interpolator.interpolate( "\\{", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "}";
+    actual = interpolator.interpolate( "\\}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "\\";
+    actual = interpolator.interpolate( "\\", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "a")
+  public void testUnSuccessfulInterpolation() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "foo";  // missing {}
+    String actual = interpolator.interpolate( "foo", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+
+    expected = "#{foo  {}";
+    actual = interpolator.interpolate( "#{foo  {}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "a")
+  public void testUnknownTokenInterpolation() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "{bar}";  // unknown token {}
+    String actual = interpolator.interpolate( "{bar}", context );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "c")
+  public void testParametersAreExtractedFromBeanValidationProviderBundle() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( Person.class, "birthday" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String key = "{javax.validation.constraints.Past.message}"; // Past is a built-in constraint so the provider must provide a default message
+    String actual = interpolator.interpolate( key, context );
+    assertFalse(
+        key.equals( actual ),
+        "There should have been a message interpolation from the bean validator provider bundle."
+    );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "g")
+  public void testConstraintAttributeValuesAreInterpolated() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "bar" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "size must be between 5 and 10";
+    String actual = interpolator.interpolate( ( String ) descriptor.getAttributes().get( "message" ), context );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "h")
+  public void testMessageInterpolationWithLocale() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String expected = "kann nicht null sein";
+    // TODO(nchalko) i18n
+    //GwtLocaleFactory localeFactory = GWT.create(GwtLocaleFactory.class);
+    GwtLocale german = null;  //localeFactory.fromComponents("de","","","");
+    String actual = interpolator.interpolate(
+        ( String ) descriptor.getAttributes().get( "message" ), context, german
+    );
+    assertEquals( actual, expected, "Wrong substitution" );
+  }
+
+  @Test
+  @SpecAssertion(section = "4.3.1.1", id = "i")
+  public void testIfNoLocaleIsSpecifiedTheDefaultLocaleIsAssumed() {
+    MessageInterpolator interpolator = getDefaultMessageInterpolator();
+    ConstraintDescriptor<?> descriptor = getDescriptorFor( DummyEntity.class, "foo" );
+    String messageTemplate = ( String ) descriptor.getAttributes().get( "message" );
+    MessageInterpolator.Context context = new TestContext( descriptor );
+
+    String messageInterpolatedWithNoLocale = interpolator.interpolate( messageTemplate, context );
+    // TODO(nchalko) i18n
+    //GwtLocaleFactory localeFactory = GWT.create(GwtLocaleFactory.class);
+    GwtLocale defaultLocale = null; // localeFactory.getDefault();
+    String messageInterpolatedWithDefaultLocale = interpolator.interpolate(
+        messageTemplate, context,defaultLocale
+    );
+
+    assertEquals( messageInterpolatedWithNoLocale, messageInterpolatedWithDefaultLocale, "Wrong substitution" );
+  }
+
+  private ConstraintDescriptor<?> getDescriptorFor(Class<?> clazz, String propertyName) {
+    Validator validator = getValidatorUnderTest();
+    return validator.getConstraintsForClass( clazz )
+        .getConstraintsForProperty( propertyName )
+        .getConstraintDescriptors()
+        .iterator()
+        .next();
+  }
+
+  public class TestContext implements MessageInterpolator.Context {
+    ConstraintDescriptor<?> descriptor;
+
+    TestContext(ConstraintDescriptor<?> descriptor) {
+      this.descriptor = descriptor;
+    }
+
+    public ConstraintDescriptor<?> getConstraintDescriptor() {
+      return descriptor;
+    }
+
+    public Object getValidatedValue() {
+      return null;
+    }
+  }
+
+  public class DummyEntity {
+    @NotNull
+    String foo;
+
+    @Size(min = 5, max = 10, message = "size must be between {min} and {max}")
+    String bar;
+
+    @Max(value = 10, message = "{replace.in.user.bundle1}")
+    String fubar;
+
+    @NotNull(message = "messages can also be overridden at constraint declaration.")
+    String snafu;
+  }
+
+  public class Person {
+
+    String name;
+
+    @Past
+    Date birthday;
+  }
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTest.gwt.xml
index 779fe81..3e949ba 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.constraints.application.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.constraints.application.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidatorFactory.java
similarity index 78%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidatorFactory.java
index d9e7e23..cf77183 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/application/TckTestValidatorFactory.java
@@ -16,8 +16,9 @@
 package com.google.gwt.sample.validationtck.constraints.application;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.constraints.application.Building;
 import org.hibernate.jsr303.tck.tests.constraints.application.SuperWoman;
@@ -27,10 +28,10 @@
 import javax.validation.Validator;
 
 /**
- * {@link Validator} implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface for {@link GWT#create(Class)}.
    */
@@ -39,7 +40,8 @@
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml
index a2b50cc..7710cf0 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.constraints.constraintcomposition.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.constraints.constraintcomposition.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidatorFactory.java
similarity index 75%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidatorFactory.java
index 76c1531..0d6bfd8 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/constraintcomposition/TckTestValidatorFactory.java
@@ -16,8 +16,9 @@
 package com.google.gwt.sample.validationtck.constraints.constraintcomposition;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.Address;
 import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.FrenchAddress;
@@ -28,23 +29,24 @@
 import javax.validation.Validator;
 
 /**
- * {@link Validator} implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface for {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
       Address.class, FrenchAddress.class, Friend.class, GermanAddress.class,
       Shoe.class
-  // TODO(nchalko) handle ConstraintDefinitionException
-  // ConstraintCompositionTest.DummyEntityWithZipCode.class
+      // TODO(nchalko) handle ConstraintDefinitionException
+      // ConstraintCompositionTest.DummyEntityWithZipCode.class
   })
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTest.gwt.xml
index c12157b..f295c1a 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.constraints.groups.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.constraints.groups.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidatorFactory.java
similarity index 77%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidatorFactory.java
index c1f014a..22409be 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/groups/TckTestValidatorFactory.java
@@ -16,8 +16,9 @@
 package com.google.gwt.sample.validationtck.constraints.groups;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.constraints.groups.Animal;
 import org.hibernate.jsr303.tck.tests.constraints.groups.Book;
@@ -27,10 +28,10 @@
 import javax.validation.Validator;
 
 /**
- * Validator implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface to {@link GWT#create(Class)}.
    */
@@ -38,7 +39,8 @@
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTest.gwt.xml
index a28c2fe..1708896 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.constraints.inheritance.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.constraints.inheritance.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidatorFactory.java
similarity index 74%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidatorFactory.java
index dd13747..7f35236 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/constraints/inheritance/TckTestValidatorFactory.java
@@ -16,18 +16,19 @@
 package com.google.gwt.sample.validationtck.constraints.inheritance;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.constraints.inheritance.Bar;
 
 import javax.validation.Validator;
 
 /**
- * Validator implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface to {@link GWT#create(Class)}.
    */
@@ -35,7 +36,8 @@
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationGwtSuite.java
similarity index 72%
copy from user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java
copy to samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationGwtSuite.java
index e9a711a..fc97db1 100644
--- a/user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationGwtSuite.java
@@ -13,21 +13,20 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.validation.example.client;
+package com.google.gwt.sample.validationtck.messageinterpolation;
 
 import com.google.gwt.junit.tools.GWTTestSuite;
 
 import junit.framework.Test;
 
 /**
- * All Constraints tests that GWTTestCase.
+ * Tck Tests for the {@code messageinterpolation} package.
  */
-public class ExampleValidationClientGwtSuite {
+public class MessageInterpolationGwtSuite {
   public static Test suite() {
     GWTTestSuite suite = new GWTTestSuite(
-        "Validation Example tests that require GWT");
-    suite.addTestSuite(AuthorTest.class);
+        "TCK for GWT Validation, messageinterpolation package");
+    suite.addTestSuite(MessageInterpolationTest.class);
     return suite;
   }
-
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationTest.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationTest.java
new file mode 100644
index 0000000..284cf03
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/MessageInterpolationTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.messageinterpolation;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Wraps
+ * {@link org.hibernate.jsr303.tck.tests.messageinterpolation.MessageInterpolationTest}
+ * .
+ */
+public class MessageInterpolationTest extends GWTTestCase {
+  private final org.hibernate.jsr303.tck.tests.messageinterpolation.MessageInterpolationTest delegate =
+    new org.hibernate.jsr303.tck.tests.messageinterpolation.MessageInterpolationTest();
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.sample.validationtck.messageinterpolation.TckTest";
+  }
+
+  public void testConstraintAttributeValuesAreInterpolated() {
+    delegate.testConstraintAttributeValuesAreInterpolated();
+  }
+
+  public void testDefaultMessageInterpolatorIsNotNull() {
+    delegate.testDefaultMessageInterpolatorIsNotNull();
+  }
+
+  public void testIfNoLocaleIsSpecifiedTheDefaultLocaleIsAssumed() {
+    delegate.testIfNoLocaleIsSpecifiedTheDefaultLocaleIsAssumed();
+  }
+
+  public void testLiteralCurlyBraces() {
+    delegate.testLiteralCurlyBraces();
+  }
+
+  public void testMessageInterpolationWithLocale() {
+    delegate.testMessageInterpolationWithLocale();
+  }
+
+  public void testMessagesCanBeOverriddenAtConstraintLevel() {
+    delegate.testMessagesCanBeOverriddenAtConstraintLevel();
+  }
+
+  public void testParametersAreExtractedFromBeanValidationProviderBundle() {
+    delegate.testParametersAreExtractedFromBeanValidationProviderBundle();
+  }
+
+  public void testRecursiveMessageInterpolation() {
+    delegate.testRecursiveMessageInterpolation();
+  }
+
+  public void testSuccessfulInterpolationOfValidationMessagesValue() {
+    delegate.testSuccessfulInterpolationOfValidationMessagesValue();
+  }
+
+  public void testUnknownTokenInterpolation() {
+    delegate.testUnknownTokenInterpolation();
+  }
+
+  public void testUnSuccessfulInterpolation() {
+    delegate.testUnSuccessfulInterpolation();
+  }
+
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTest.gwt.xml
new file mode 100644
index 0000000..b0197cd
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTest.gwt.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.1/distro-source/core/src/gwt-module.dtd">
+<!--
+  Copyright 2010 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License. You may obtain a copy of
+  the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+  License for the specific language governing permissions and limitations under
+  the License.
+-->
+<module>
+  <inherits name="com.google.gwt.sample.validationtck.ValidationTck" />
+  <source path="">
+    <include name="*.java" />
+    <exclude name="super" />
+  </source>
+  <replace-with class="com.google.gwt.sample.validationtck.messageinterpolation.TckUserValidationMessageProvider">
+    <when-type-is class="com.google.gwt.validation.client.UserValidationMessagesResolver" />
+  </replace-with>
+  <replace-with class="com.google.gwt.sample.validationtck.messageinterpolation.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
+  </replace-with>
+</module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTestValidatorFactory.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTestValidatorFactory.java
new file mode 100644
index 0000000..aadb753
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckTestValidatorFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.messageinterpolation;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
+
+import org.hibernate.jsr303.tck.tests.messageinterpolation.MessageInterpolationTest.DummyEntity;
+import org.hibernate.jsr303.tck.tests.messageinterpolation.MessageInterpolationTest.Person;
+
+import javax.validation.Validator;
+
+/**
+ * {@link AbstractGwtValidatorFactory} implementation that uses
+ * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
+ */
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
+  /**
+   * Marker Interface for {@link GWT#create(Class)}.
+   */
+  @GwtValidation(value = {DummyEntity.class, Person.class})
+  public static interface GwtValidator extends Validator {
+  }
+
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
+  }
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckUserValidationMessageProvider.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckUserValidationMessageProvider.java
new file mode 100644
index 0000000..d0c0fb5
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/TckUserValidationMessageProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.validationtck.messageinterpolation;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.ConstantsWithLookup;
+import com.google.gwt.validation.client.AbstractValidationMessageResolver;
+import com.google.gwt.validation.client.UserValidationMessagesResolver;
+
+/**
+ * Custom messages from {@link ValidationMessages}.
+ */
+public class TckUserValidationMessageProvider extends
+    AbstractValidationMessageResolver implements
+    UserValidationMessagesResolver {
+
+  public TckUserValidationMessageProvider() {
+    super((ConstantsWithLookup) GWT.create(ValidationMessages.class));
+  }
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.java
new file mode 100644
index 0000000..9506013
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.java
@@ -0,0 +1,44 @@
+package com.google.gwt.sample.validationtck.messageinterpolation;
+
+/**
+ * Interface to represent the constants contained in resource bundle:
+ * 'ValidationMessages.properties'.
+ */
+public interface ValidationMessages extends com.google.gwt.i18n.client.ConstantsWithLookup {
+
+  /**
+   * Translated "replacement worked".
+   *
+   * @return translated "replacement worked"
+   */
+  @DefaultStringValue("replacement worked")
+  @Key("foo")
+  String foo();
+
+  /**
+   * Translated "may not be null".
+   *
+   * @return translated "may not be null"
+   */
+  @DefaultStringValue("may not be null")
+  @Key("javax.validation.constraints.NotNull.message")
+  String javax_validation_constraints_NotNull_message();
+
+  /**
+   * Translated "{replace.in.user.bundle2}".
+   *
+   * @return translated "{replace.in.user.bundle2}"
+   */
+  @DefaultStringValue("{replace.in.user.bundle2}")
+  @Key("replace.in.user.bundle1")
+  String replace_in_user_bundle1();
+
+  /**
+   * Translated "recursion worked".
+   *
+   * @return translated "recursion worked"
+   */
+  @DefaultStringValue("recursion worked")
+  @Key("replace.in.user.bundle2")
+  String replace_in_user_bundle2();
+}
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.properties b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.properties
new file mode 100644
index 0000000..f22947e
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages.properties
@@ -0,0 +1,4 @@
+javax.validation.constraints.NotNull.message=may not be null
+foo=replacement worked
+replace.in.user.bundle1={replace.in.user.bundle2}
+replace.in.user.bundle2=recursion worked
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages_de.properties b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages_de.properties
new file mode 100644
index 0000000..5485599
--- /dev/null
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/messageinterpolation/ValidationMessages_de.properties
@@ -0,0 +1 @@
+javax.validation.constraints.NotNull.message=kann nicht null sein
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTest.gwt.xml
index 93f82e8..6e19709 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.metadata.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.metadata.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidatorFactory.java
similarity index 76%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidatorFactory.java
index 4c5cb7d..4b8ace9 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/metadata/TckTestValidatorFactory.java
@@ -16,8 +16,9 @@
 package com.google.gwt.sample.validationtck.metadata;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.metadata.Account;
 import org.hibernate.jsr303.tck.tests.metadata.Customer;
@@ -28,9 +29,9 @@
 import javax.validation.Validator;
 
 /**
- * Test Validator for {@link MetadataGwtSuite}.
+ * Test {@link AbstractGwtValidatorFactory} for {@link MetadataGwtSuite}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface to {@link GWT#create(Class)}.
    */
@@ -40,7 +41,8 @@
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTest.gwt.xml
index cac71d1..9dce00e 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.validation.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.validation.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidatorFactory.java
similarity index 71%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidatorFactory.java
index 707b44a..a5fb694 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/validation/TckTestValidatorFactory.java
@@ -16,10 +16,12 @@
 package com.google.gwt.sample.validationtck.validation;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.validation.Actor;
+import org.hibernate.jsr303.tck.tests.validation.Address;
 import org.hibernate.jsr303.tck.tests.validation.BadlyBehavedEntity;
 import org.hibernate.jsr303.tck.tests.validation.Customer;
 import org.hibernate.jsr303.tck.tests.validation.Engine;
@@ -27,20 +29,21 @@
 import javax.validation.Validator;
 
 /**
- * {@link Validator} implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface for {@link GWT#create(Class)}.
    */
   @GwtValidation(value = {
-      Actor.class, BadlyBehavedEntity.class, Engine.class,
+      Address.class, Actor.class, BadlyBehavedEntity.class, Engine.class,
       Customer.class})
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTest.gwt.xml b/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTest.gwt.xml
index 03b25d6..fbb2c15 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTest.gwt.xml
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTest.gwt.xml
@@ -21,7 +21,7 @@
     <include name="*.java" />
     <exclude name="super" />
   </source>
-  <replace-with class="com.google.gwt.sample.validationtck.validatorfactory.TckTestValidator">
-    <when-type-is class="javax.validation.Validator"/>
+  <replace-with class="com.google.gwt.sample.validationtck.validatorfactory.TckTestValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory"/>
   </replace-with>
 </module>
\ No newline at end of file
diff --git a/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidator.java b/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidatorFactory.java
similarity index 66%
rename from samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidator.java
rename to samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidatorFactory.java
index 3e5438a..2e7a862 100644
--- a/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidator.java
+++ b/samples/validationtck/test/com/google/gwt/sample/validationtck/validatorfactory/TckTestValidatorFactory.java
@@ -16,26 +16,29 @@
 package com.google.gwt.sample.validationtck.validatorfactory;
 
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.validation.client.AbstractValidator;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
 import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
 
 import org.hibernate.jsr303.tck.tests.validatorfactory.CustomConstraintValidatorTest.Dummy;
+import org.hibernate.jsr303.tck.tests.validatorfactory.CustomConstraintValidatorTest.SecondDummy;
 
 import javax.validation.Validator;
 
 /**
- * {@link Validator} implementation that uses
+ * {@link AbstractGwtValidatorFactory} implementation that uses
  * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
  */
-public final class TckTestValidator extends AbstractValidator {
+public final class TckTestValidatorFactory extends AbstractGwtValidatorFactory {
   /**
    * Marker Interface for {@link GWT#create(Class)}.
    */
-  @GwtValidation(value = {Dummy.class})
+  @GwtValidation(value = {Dummy.class, SecondDummy.class})
   public static interface GwtValidator extends Validator {
   }
 
-  public TckTestValidator() {
-    super((Validator) GWT.create(GwtValidator.class));
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
   }
 }
diff --git a/user/build.xml b/user/build.xml
index 0dfcaa2..7ff87e8 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -147,6 +147,7 @@
         <exclude name="javax/validation/super/javax/validation/Configuration.java"/>
         <exclude name="javax/validation/super/javax/validation/Validation.java"/>
         <exclude name="org/hibernate/validator/super/org/hibernate/validator/**/*.java"/>
+        <exclude name="org/hibernate/validator/ValidationMessages.java"/>
       </fileset>
       <fileset dir="super/com/google/gwt/emul" />
       <fileset dir="super/com/google/gwt/junit/translatable" />
diff --git a/user/src/com/google/gwt/validation/Validation.gwt.xml b/user/src/com/google/gwt/validation/Validation.gwt.xml
index 813b3be..063a83e 100644
--- a/user/src/com/google/gwt/validation/Validation.gwt.xml
+++ b/user/src/com/google/gwt/validation/Validation.gwt.xml
@@ -35,10 +35,7 @@
     class="com.google.gwt.validation.client.GwtTraversableResolver">
     <when-type-is class="javax.validation.TraversableResolver" />
   </replace-with>
-  <replace-with
-    class="com.google.gwt.validation.client.spi.GwtValidationProvider">
-    <when-type-is class="javax.validation.spi.ValidationProvider" />
-  </replace-with>
+
   <replace-with
     class="com.google.gwt.validation.client.GwtValidationProviderResolver">
     <when-type-is class="javax.validation.ValidationProviderResolver" />
@@ -46,11 +43,13 @@
   <replace-with class="com.google.gwt.validation.client.GwtValidatorContext">
     <when-type-is class="javax.validation.ValidatorContext" />
   </replace-with>
-  <replace-with class="com.google.gwt.validation.client.GwtValidatorFactory">
-    <when-type-is class="javax.validation.ValidatorFactory" />
+  <replace-with class="com.google.gwt.validation.client.NullUserValidationMessageResolver">
+    <!-- User can override this to have Custom messages -->
+    <when-type-is class="com.google.gwt.validation.client.UserValidationMessagesResolver" />
   </replace-with>
-  <replace-with class="com.google.gwt.validation.client.Validation">
-    <when-type-is class="javax.validation.Validation" />
+  <replace-with
+    class="com.google.gwt.validation.client.spi.GwtValidationProvider">
+    <when-type-is class="javax.validation.spi.ValidationProvider" />
   </replace-with>
 
   <!-- Generators -->
diff --git a/user/src/com/google/gwt/validation/client/AbstractGwtValidatorFactory.java b/user/src/com/google/gwt/validation/client/AbstractGwtValidatorFactory.java
new file mode 100644
index 0000000..c4fbaa0
--- /dev/null
+++ b/user/src/com/google/gwt/validation/client/AbstractGwtValidatorFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
+
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.MessageInterpolator;
+import javax.validation.TraversableResolver;
+import javax.validation.Validator;
+import javax.validation.ValidatorContext;
+import javax.validation.ValidatorFactory;
+
+/**
+ * Abstract {@link ValidatorFactory} that delegates to a GWT generated
+ * {@link Validator}.
+ * <p>
+ * Extend this class create and implement createValidator
+ *
+ * <pre>
+ * public class MyValidatorFactory extends AbstractGwtValidatorFactory {
+ *   @GwtValidation(value = {Pojo.class,Other.class})
+ *   public static interface GwtValidator extends Validator {
+ *   }
+ *
+ *   public AbstractGwtValidator createValidator (){
+ *     return GWT.create(GwtValidator.class));
+ *   }
+ * }
+ * </pre>
+ * <p>
+ * Then add a line like this to your Gwt Module config (gwt.xml) file.
+ *
+ * <pre>
+ * &lt;replace-with class="com.example.MyValidatorFactory">
+ *   &lt;when-type-is class="javax.validation.ValidatorFactory"/>
+ * &lt;/replace-with>
+ * </pre>
+ */
+public abstract class AbstractGwtValidatorFactory implements ValidatorFactory {
+
+  /**
+   * Implement this method to returns a {@link GWT#create}ed {@link Validator}
+   * annotated with {@link GwtValidation}.
+   *
+   * @return newly created Validator
+   */
+  public abstract AbstractGwtValidator createValidator();
+
+  public final ConstraintValidatorFactory getConstraintValidatorFactory() {
+    return GWT.create(ConstraintValidatorFactory.class);
+  }
+
+  public final MessageInterpolator getMessageInterpolator() {
+    return new GwtMessageInterpolator();
+  }
+
+  public final TraversableResolver getTraversableResolver() {
+    return GWT.create(TraversableResolver.class);
+  }
+
+  public final Validator getValidator() {
+    AbstractGwtValidator validator = createValidator();
+    validator.init(getConstraintValidatorFactory(), getMessageInterpolator(),
+        getTraversableResolver());
+    return validator;
+  }
+
+  public final <T> T unwrap(Class<T> type) {
+    // TODO(nchalko implement
+    return null;
+  }
+
+  public final ValidatorContext usingContext() {
+    return GWT.create(ValidatorContext.class);
+  }
+}
diff --git a/user/src/com/google/gwt/validation/client/AbstractValidationMessageResolver.java b/user/src/com/google/gwt/validation/client/AbstractValidationMessageResolver.java
new file mode 100644
index 0000000..6c7eaa0
--- /dev/null
+++ b/user/src/com/google/gwt/validation/client/AbstractValidationMessageResolver.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+import com.google.gwt.i18n.client.ConstantsWithLookup;
+
+import java.util.MissingResourceException;
+
+/**
+ * ValidationMessageResolver using a {@link ConstantsWithLookup} source.
+ */
+public abstract class AbstractValidationMessageResolver {
+  private final ConstantsWithLookup messages;
+
+  protected AbstractValidationMessageResolver(ConstantsWithLookup messages) {
+    this.messages = messages;
+  }
+
+  public final String get(String key) {
+    try {
+      // Replace "." with "_" in the key to match what ConstantsImplCreator
+      // does.
+      return key == null ? null : messages.getString(key.replace(".", "_"));
+    } catch (MissingResourceException e) {
+      return null;
+    }
+  }
+}
diff --git a/user/src/com/google/gwt/validation/client/AbstractValidator.java b/user/src/com/google/gwt/validation/client/AbstractValidator.java
deleted file mode 100644
index ddef4e6..0000000
--- a/user/src/com/google/gwt/validation/client/AbstractValidator.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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;
-
-import java.util.Set;
-
-import javax.validation.ConstraintViolation;
-import javax.validation.Validator;
-import javax.validation.metadata.BeanDescriptor;
-
-/**
- * Abstract {@link Validator} that delegates to a GWT generated validator.
- * <p>
- * Extend this class create a default no arg constructor like.
- *
- * <pre>
- * public class MyValidator {
- *   @GwtValidation(value = {Pojo.class,Other.class})
- *   public static interface GwtValidator extends Validator {
- *   }
- *
- *   MyValidator() {
- *     super((Validator) GWT.create(GwtValidator.class));
- *   }
- * }
- * </pre>
- * <p>
- * Then add a line like this to your Gwt Module config (gwt.xml) file.
- *
- * <pre>
- * &lt;replace-with class="com.example.MyValidator.GwtValidator">
- *   &lt;when-type-is class="javax.validation.Validator"/>
- * &lt;/replace-with>
- * </pre>
- */
-public abstract class AbstractValidator implements Validator {
-
-  private final Validator validator;
-
-  /**
-   * Pass a GWT created {@link Validator} to this constructor.
-   */
-  public AbstractValidator(Validator validator) {
-    super();
-    this.validator = validator;
-  }
-
-  public final BeanDescriptor getConstraintsForClass(Class<?> clazz) {
-    return validator.getConstraintsForClass(clazz);
-  }
-
-  public final <T> T unwrap(Class<T> type) {
-    return validator.unwrap(type);
-  }
-
-  public final <T> Set<ConstraintViolation<T>> validate(T object,
-      Class<?>... groups) {
-    return validator.validate(object, groups);
-  }
-
-  public final <T> Set<ConstraintViolation<T>> validateProperty(T object,
-      String propertyName, Class<?>... groups) {
-    return validator.validateProperty(object, propertyName, groups);
-  }
-
-  public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
-      String propertyName, Object value,
-      Class<?>... groups) {
-        return validator.validateValue(beanType, propertyName, value, groups);
-      }
-}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/validation/client/BaseMessageInterpolator.java b/user/src/com/google/gwt/validation/client/BaseMessageInterpolator.java
index 5ad30ed..9feb57d 100644
--- a/user/src/com/google/gwt/validation/client/BaseMessageInterpolator.java
+++ b/user/src/com/google/gwt/validation/client/BaseMessageInterpolator.java
@@ -15,15 +15,148 @@
  */
 package com.google.gwt.validation.client;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.regexp.shared.MatchResult;
+import com.google.gwt.regexp.shared.RegExp;
+
+import java.util.Map;
+
 import javax.validation.MessageInterpolator;
+import javax.validation.metadata.ConstraintDescriptor;
 
 /**
  * Base GWT {@link MessageInterpolator}.
  */
 public abstract class BaseMessageInterpolator implements MessageInterpolator {
 
-  public final String interpolate(String messageTemplate, Context context) {
-    // TODO(nchalko) implement.
-    return null;
+  /**
+   * Implementation of {@link Context}.
+   */
+  public static class ContextImpl implements Context {
+
+    private final ConstraintDescriptor<?> constraintDescriptor;
+    private final Object value;
+
+    public ContextImpl(ConstraintDescriptor<?> constraintDescriptor, Object value) {
+      this.constraintDescriptor = constraintDescriptor;
+      this.value = value;
+    }
+
+    public ConstraintDescriptor<?> getConstraintDescriptor() {
+      return constraintDescriptor;
+    }
+
+    public Object getValidatedValue() {
+      return value;
+    }
   }
-}
\ No newline at end of file
+
+  // local version because guava is included.
+  private static interface Function<F, T> {
+    T apply(F from);
+  }
+
+  /**
+   * Regular expression used to do message interpolation.
+   */
+  private static final RegExp MESSAGE_PARAMETER_PATTERN = RegExp.compile(
+      "(\\{[^\\}]+?\\})", "g");
+
+  // Visible for testing
+  static Function<String, String> createAnnotationReplacer(
+      final Map<String, Object> map) {
+    return new Function<String, String>() {
+
+      public String apply(String from) {
+        Object object = map.get(from);
+        return object == null ? null : object.toString();
+      }
+    };
+  }
+
+  private static Function<String, String> createReplacer(
+      final ValidationMessageResolver messageResolver) {
+    return new Function<String, String>() {
+      public String apply(String from) {
+        Object object = messageResolver.get(from);
+        return object == null ? null : object.toString();
+      }
+    };
+  }
+
+  /**
+   * Replaces keys using the Default Validation Provider properties.
+   */
+  private final Function<String, String> providerReplacer =
+      createReplacer((ValidationMessageResolver)
+          GWT.create(ProviderValidationMessageResolver.class));
+
+  /**
+   * Replaces keys using the Validation User custom properties.
+   */
+  private final Function<String, String> userReplacer =
+      createReplacer((ValidationMessageResolver)
+          GWT.create(UserValidationMessagesResolver.class));
+
+  public String interpolate(String messageTemplate, Context context) {
+    return gwtInterpolate(messageTemplate, context, null);
+  }
+
+  protected String gwtInterpolate(String message, Context context,
+      GwtLocale locale) {
+    // see Section 4.3.1.1
+    String resolvedMessage = message;
+    String step1message;
+
+    // TODO(nchalko) Add a safety to make sure this does not loop forever.
+    do {
+      do {
+        step1message = resolvedMessage;
+
+        // Step 1 Replace message parameters using custom user messages
+        // repeat
+        resolvedMessage = replaceParameters(resolvedMessage, userReplacer);
+      } while (!step1message.equals(resolvedMessage));
+
+      // Step2 Replace message parameter using the default provider messages.
+      resolvedMessage = replaceParameters(resolvedMessage, providerReplacer);
+
+      // Step 3 repeat from step 1 if step 2 made changes.
+    } while (!step1message.equals(resolvedMessage));
+
+    // step 4 resolve annotation attributes
+    resolvedMessage = replaceParameters(
+        resolvedMessage,
+        createAnnotationReplacer(context.getConstraintDescriptor().getAttributes()));
+
+    // Remove escapes (4.3.1)
+    resolvedMessage = resolvedMessage.replace("\\{", "{");
+    resolvedMessage = resolvedMessage.replace("\\}", "}");
+    resolvedMessage = resolvedMessage.replace("\\\\", "\\");
+    return resolvedMessage;
+  }
+
+  protected String replaceParameters(String message,
+      Function<String, String> replacer) {
+    StringBuffer sb = new StringBuffer();
+    int index = 0;
+
+    MatchResult matcher;
+    while ((matcher = MESSAGE_PARAMETER_PATTERN.exec(message)) != null) {
+      String matched = matcher.getGroup(0);
+      sb.append(message.substring(index, matcher.getIndex()));
+      Object value = replacer.apply(removeCurlyBrace(matched));
+      sb.append(value == null ? matched : value);
+      index = MESSAGE_PARAMETER_PATTERN.getLastIndex();
+    }
+    if (index < message.length()) {
+      sb.append(message.substring(index));
+    }
+    return sb.toString();
+  }
+
+  private String removeCurlyBrace(String parameter) {
+    return parameter.substring(1, parameter.length() - 1);
+  }
+}
diff --git a/user/src/com/google/gwt/validation/client/GwtValidatorContext.java b/user/src/com/google/gwt/validation/client/GwtValidatorContext.java
index 282361e..259b869 100644
--- a/user/src/com/google/gwt/validation/client/GwtValidatorContext.java
+++ b/user/src/com/google/gwt/validation/client/GwtValidatorContext.java
@@ -15,37 +15,61 @@
  */
 package com.google.gwt.validation.client;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
+
 import javax.validation.ConstraintValidatorFactory;
 import javax.validation.MessageInterpolator;
 import javax.validation.TraversableResolver;
 import javax.validation.Validator;
 import javax.validation.ValidatorContext;
+import javax.validation.ValidatorFactory;
 
 /**
  * GWT {@link ValidatorContext}.
  */
 public class GwtValidatorContext implements ValidatorContext {
 
+  private final AbstractGwtValidatorFactory validatorFactory = GWT.create(ValidatorFactory.class);
+
+  private ConstraintValidatorFactory constraintValidatorfactory = validatorFactory.getConstraintValidatorFactory();
+  private MessageInterpolator messageInterpolator = validatorFactory.getMessageInterpolator();
+  private TraversableResolver traversableResolver = validatorFactory.getTraversableResolver();
+
   public ValidatorContext constraintValidatorFactory(
       ConstraintValidatorFactory factory) {
-    // TODO(nchalko) implement
+    if (factory == null) {
+      this.constraintValidatorfactory = GWT.create(ConstraintValidatorFactory.class);
+    } else {
+      this.constraintValidatorfactory = factory;
+    }
     return this;
   }
 
   public Validator getValidator() {
-    // TODO(nchalko) implement
-    return null;
+    AbstractGwtValidator validator = validatorFactory.createValidator();
+    validator.init(constraintValidatorfactory, messageInterpolator,
+        traversableResolver);
+    return validator;
   }
 
   public ValidatorContext messageInterpolator(
       MessageInterpolator messageInterpolator) {
-    // TODO(nchalko) implement
+    if (messageInterpolator == null) {
+      this.messageInterpolator = GWT.create(MessageInterpolator.class);
+    } else {
+      this.messageInterpolator = messageInterpolator;
+    }
     return this;
   }
 
   public ValidatorContext traversableResolver(
       TraversableResolver traversableResolver) {
-    // TODO(nchalko) implement
+    if (traversableResolver == null) {
+      this.traversableResolver = GWT.create(TraversableResolver.class);
+    } else {
+      this.traversableResolver = traversableResolver;
+    }
     return this;
   }
 
diff --git a/user/src/com/google/gwt/validation/client/GwtValidatorFactory.java b/user/src/com/google/gwt/validation/client/GwtValidatorFactory.java
deleted file mode 100644
index ce2e5c8..0000000
--- a/user/src/com/google/gwt/validation/client/GwtValidatorFactory.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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;
-
-import com.google.gwt.core.client.GWT;
-
-import javax.validation.ConstraintValidatorFactory;
-import javax.validation.MessageInterpolator;
-import javax.validation.TraversableResolver;
-import javax.validation.Validator;
-import javax.validation.ValidatorContext;
-import javax.validation.ValidatorFactory;
-
-/**
- * GWT Specific Validator Factory.
- */
-public class GwtValidatorFactory implements ValidatorFactory {
-
-  public ConstraintValidatorFactory getConstraintValidatorFactory() {
-    return GWT.create(ConstraintValidatorFactory.class);
-  }
-
-  public MessageInterpolator getMessageInterpolator() {
-    return GWT.create(MessageInterpolator.class);
-  }
-
-  public TraversableResolver getTraversableResolver() {
-    return GWT.create(TraversableResolver.class);
-  }
-
-  public Validator getValidator() {
-    return GWT.create(Validator.class);
-  }
-
-  public <T> T unwrap(Class<T> type) {
-    // TODO(nchalko implement
-    return null;
-  }
-
-  public ValidatorContext usingContext() {
-    return GWT.create(ValidatorContext.class);
-  }
-
-}
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/src/com/google/gwt/validation/client/NullUserValidationMessageResolver.java
similarity index 65%
copy from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
copy to user/src/com/google/gwt/validation/client/NullUserValidationMessageResolver.java
index 03e87ad..0cc8a3f 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/src/com/google/gwt/validation/client/NullUserValidationMessageResolver.java
@@ -15,19 +15,13 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.tools.GWTTestSuite;
-
-import junit.framework.Test;
-
 /**
- * All validation client GWT tests.
+ * Always resolves message keys to null.
  */
-public class ValidationClientGwtSuite {
+public class NullUserValidationMessageResolver implements
+    UserValidationMessagesResolver {
 
-  public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test suite for all validation code.");
-    suite.addTestSuite(SimpleSampleTest.class);
-    return suite;
+  public String get(String key) {
+    return null;
   }
 }
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/src/com/google/gwt/validation/client/ProviderValidationMessageResolver.java
similarity index 64%
copy from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
copy to user/src/com/google/gwt/validation/client/ProviderValidationMessageResolver.java
index 03e87ad..51a461c 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/src/com/google/gwt/validation/client/ProviderValidationMessageResolver.java
@@ -15,19 +15,8 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.tools.GWTTestSuite;
-
-import junit.framework.Test;
-
 /**
- * All validation client GWT tests.
+ * Validation Providers implement this to resolve Validation Messages.
  */
-public class ValidationClientGwtSuite {
-
-  public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test suite for all validation code.");
-    suite.addTestSuite(SimpleSampleTest.class);
-    return suite;
-  }
+public interface ProviderValidationMessageResolver extends ValidationMessageResolver {
 }
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/src/com/google/gwt/validation/client/UserValidationMessagesResolver.java
similarity index 64%
copy from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
copy to user/src/com/google/gwt/validation/client/UserValidationMessagesResolver.java
index 03e87ad..41a0620 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/src/com/google/gwt/validation/client/UserValidationMessagesResolver.java
@@ -15,19 +15,9 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.tools.GWTTestSuite;
-
-import junit.framework.Test;
-
 /**
- * All validation client GWT tests.
+ * Validation Providers implement this to resolve Validation Messages. including
+ * overriding the default {@link ProviderValidationMessageResolver}.
  */
-public class ValidationClientGwtSuite {
-
-  public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test suite for all validation code.");
-    suite.addTestSuite(SimpleSampleTest.class);
-    return suite;
-  }
+public interface UserValidationMessagesResolver extends ValidationMessageResolver {
 }
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/src/com/google/gwt/validation/client/ValidationMessageResolver.java
similarity index 64%
copy from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
copy to user/src/com/google/gwt/validation/client/ValidationMessageResolver.java
index 03e87ad..5b96dd9 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/src/com/google/gwt/validation/client/ValidationMessageResolver.java
@@ -15,19 +15,16 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.tools.GWTTestSuite;
-
-import junit.framework.Test;
-
 /**
- * All validation client GWT tests.
+ * Users and Validation providers implement this to resolve ValidationMessages
  */
-public class ValidationClientGwtSuite {
+public interface ValidationMessageResolver {
 
-  public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test suite for all validation code.");
-    suite.addTestSuite(SimpleSampleTest.class);
-    return suite;
-  }
-}
+  /**
+   * Lookup the value of the given key.
+   *
+   * @param key the key to find
+   * @return the value of the key or {@code null} if not found.
+   */
+  String get(String key);
+}
\ No newline at end of file
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 05a949b..62b482d 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.BaseMessageInterpolator.ContextImpl;
+
 import java.lang.annotation.Annotation;
 import java.util.Collection;
 import java.util.Collections;
@@ -25,6 +27,7 @@
 
 import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
 import javax.validation.groups.Default;
 
 /**
@@ -125,12 +128,15 @@
       GwtValidationContext<T> context, G object, V value,
       ConstraintDescriptorImpl<A> constraintDescriptor,
       MessageAndPath messageAndPath) {
-    // TODO(nchalko) interpolate
+    MessageInterpolator messageInterpolator = context.getMessageInterpolator();
+    ContextImpl messageContext = new ContextImpl(constraintDescriptor, value);
+    String message = messageInterpolator.interpolate(
+        messageAndPath.getMessage(), messageContext);
     ConstraintViolation<T> violation = ConstraintViolationImpl.<T> builder() //
         .setConstraintDescriptor(constraintDescriptor) //
         .setInvalidValue(value) //
         .setLeafBean(object) //
-        .setMessage(messageAndPath.getMessage()) //
+        .setMessage(message) //
         .setMessageTemplate(messageAndPath.getMessage()) //
         .setPropertyPath(messageAndPath.getPath()) //
         .setRootBean(context.getRootBean()) //
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 5e5a552..17da692 100644
--- a/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java
+++ b/user/src/com/google/gwt/validation/client/impl/AbstractGwtValidator.java
@@ -1,12 +1,12 @@
 /*
  * 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
@@ -19,6 +19,9 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.MessageInterpolator;
+import javax.validation.TraversableResolver;
 import javax.validation.ValidationException;
 import javax.validation.Validator;
 
@@ -30,9 +33,12 @@
 public abstract class AbstractGwtValidator implements Validator {
 
   private final Set<Class<?>> validGroups;
+  private ConstraintValidatorFactory factory;
+  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.
    */
@@ -40,6 +46,14 @@
     validGroups = new HashSet<Class<?>>(Arrays.asList(groups));
   }
 
+  public void init(ConstraintValidatorFactory factory,
+      MessageInterpolator messageInterpolator,
+      TraversableResolver traversableResolver) {
+    this.factory = factory;
+    this.messageInterpolator = messageInterpolator;
+    this.traversableResolver = traversableResolver;
+  }
+
   public <T> T unwrap(Class<T> type) {
     throw new ValidationException();
   }
@@ -59,4 +73,16 @@
       throw new IllegalArgumentException(name + " can not be null.");
     }
   }
+
+  protected ConstraintValidatorFactory getFactory() {
+    return factory;
+  }
+
+  protected MessageInterpolator getMessageInterpolator() {
+    return messageInterpolator;
+  }
+
+  protected TraversableResolver getTraversableResolver() {
+    return traversableResolver;
+  }
 }
diff --git a/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java b/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
index c78140e..38d6ccd 100644
--- a/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
+++ b/user/src/com/google/gwt/validation/client/impl/GwtValidationContext.java
@@ -17,12 +17,13 @@
 
 import java.lang.annotation.Annotation;
 
+import javax.validation.MessageInterpolator;
 import javax.validation.metadata.BeanDescriptor;
 import javax.validation.metadata.ConstraintDescriptor;
 
 /**
  * Context for a {@link com.google.gwt.validation.client.GwtValidation}.
- * 
+ *
  * @param <T> the type of the root bean.
  */
 public class GwtValidationContext<T> {
@@ -30,13 +31,16 @@
   private final BeanDescriptor beanDescriptor;
   private PathImpl path = new PathImpl();
   private final T rootBean;
+  private final MessageInterpolator messageInterpolator;
 
   /**
    *
    */
-  public GwtValidationContext(T rootBean, BeanDescriptor beanDescriptor) {
+  public GwtValidationContext(T rootBean, BeanDescriptor beanDescriptor,
+      MessageInterpolator messageInterpolator) {
     this.rootBean = rootBean;
     this.beanDescriptor = beanDescriptor;
+    this.messageInterpolator = messageInterpolator;
   }
 
   /**
@@ -47,7 +51,7 @@
    */
   public GwtValidationContext<T> append(String name) {
     GwtValidationContext<T> temp = new GwtValidationContext<T>(rootBean,
-        beanDescriptor);
+        beanDescriptor, messageInterpolator);
     temp.path = temp.path.append(name);
     return temp;
   }
@@ -57,6 +61,10 @@
     return new ConstraintValidatorContextImpl<A, V>(path, descriptor);
   }
 
+  public MessageInterpolator getMessageInterpolator() {
+    return messageInterpolator;
+  }
+
   public T getRootBean() {
     return rootBean;
   }
diff --git a/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java b/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
index fd8df74..a5787e3 100644
--- a/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
+++ b/user/src/com/google/gwt/validation/rebind/ValidatorCreator.java
@@ -114,13 +114,15 @@
 
   private void writeContext(SourceWriter sw, BeanHelper bean, String objectName) {
     // GwtValidationContext<T> context =
-    // new GwtValidationContext<T>(object,myBeanValidator.getConstraints());
+    // new GwtValidationContext<T>(object,myBeanValidator.getConstraints(),
+    // getMessageInterpolator());
     sw.print(GwtValidationContext.class.getSimpleName());
     sw.print("<T> context =");
     sw.print("    new " + GwtValidationContext.class.getSimpleName());
     sw.print("<T>(" + objectName + ", ");
     sw.print(bean.getValidatorInstanceName());
-    sw.print(".getConstraints()");
+    sw.print(".getConstraints(), ");
+    sw.print("getMessageInterpolator()");
     sw.println(");");
   }
 
diff --git a/user/src/com/google/gwt/validation/super/com/google/gwt/validation/client/GwtMessageInterpolator.java b/user/src/com/google/gwt/validation/super/com/google/gwt/validation/client/GwtMessageInterpolator.java
index f75bcff..f180b17 100644
--- a/user/src/com/google/gwt/validation/super/com/google/gwt/validation/client/GwtMessageInterpolator.java
+++ b/user/src/com/google/gwt/validation/super/com/google/gwt/validation/client/GwtMessageInterpolator.java
@@ -17,6 +17,8 @@
 
 import com.google.gwt.i18n.shared.GwtLocale;
 
+import javax.validation.MessageInterpolator.Context;
+
 /**
  * Simple GWT {@link javax.validation.MessageInterpolator}.
  */
@@ -25,6 +27,6 @@
 
   public String interpolate(String messageTemplate, Context context,
       GwtLocale locale) {
-    return messageTemplate;
+    return gwtInterpolate(messageTemplate,context,locale);
   }
 }
diff --git a/user/src/org/hibernate/validator/HibernateValidationMessageResolver.java b/user/src/org/hibernate/validator/HibernateValidationMessageResolver.java
new file mode 100644
index 0000000..824c017
--- /dev/null
+++ b/user/src/org/hibernate/validator/HibernateValidationMessageResolver.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.hibernate.validator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.ConstantsWithLookup;
+import com.google.gwt.validation.client.AbstractValidationMessageResolver;
+import com.google.gwt.validation.client.ProviderValidationMessageResolver;
+
+/**
+ * Hibernate default {@link ProviderValidationMessageResolver}.
+ */
+public class HibernateValidationMessageResolver extends
+    AbstractValidationMessageResolver implements
+    ProviderValidationMessageResolver {
+
+  private final ValidationMessages messages = GWT.create(ValidationMessages.class);
+
+  public HibernateValidationMessageResolver() {
+    super((ConstantsWithLookup) GWT.create(ValidationMessages.class));
+  }
+}
diff --git a/user/src/org/hibernate/validator/HibernateValidator.gwt.xml b/user/src/org/hibernate/validator/HibernateValidator.gwt.xml
index 626fd9c..8100d63 100644
--- a/user/src/org/hibernate/validator/HibernateValidator.gwt.xml
+++ b/user/src/org/hibernate/validator/HibernateValidator.gwt.xml
@@ -14,5 +14,13 @@
     <include name="NodeImpl.java"/>
     <include name="PathImpl.java"/>
   </source>
+  <source path="">
+    <include name="ValidationMessages.java"/>
+    <include name="HibernateValidationMessageResolver.java"/>
+  </source>
   <super-source path="super" />
+  <replace-with
+    class="org.hibernate.validator.HibernateValidationMessageResolver">
+    <when-type-is class="com.google.gwt.validation.client.ProviderValidationMessageResolver" />
+  </replace-with>
 </module>
diff --git a/user/src/org/hibernate/validator/README.txt b/user/src/org/hibernate/validator/README.txt
index 26e3292..008bc33 100644
--- a/user/src/org/hibernate/validator/README.txt
+++ b/user/src/org/hibernate/validator/README.txt
@@ -6,7 +6,7 @@
 
 
 Maintenance Notes.
-Test using samples/validation.
+Test using samples/validation and samples/validationtck
 
 
 NOTE
diff --git a/user/src/org/hibernate/validator/ValidationMessages.java b/user/src/org/hibernate/validator/ValidationMessages.java
new file mode 100644
index 0000000..a1fbaec
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages.java
@@ -0,0 +1,197 @@
+package org.hibernate.validator;
+
+/**
+ * Interface to represent the constants contained in resource bundle:
+ * 'validation/ValidationMessages.properties'.
+ */
+public interface ValidationMessages extends com.google.gwt.i18n.client.ConstantsWithLookup {
+
+  /**
+   * Translated "must be false".
+   *
+   * @return translated "must be false"
+   */
+  @DefaultStringValue("must be false")
+  @Key("javax.validation.constraints.AssertFalse.message")
+  String javax_validation_constraints_AssertFalse_message();
+
+  /**
+   * Translated "must be true".
+   *
+   * @return translated "must be true"
+   */
+  @DefaultStringValue("must be true")
+  @Key("javax.validation.constraints.AssertTrue.message")
+  String javax_validation_constraints_AssertTrue_message();
+
+  /**
+   * Translated "must be less than or equal to {value}".
+   *
+   * @return translated "must be less than or equal to {value}"
+   */
+  @DefaultStringValue("must be less than or equal to {value}")
+  @Key("javax.validation.constraints.DecimalMax.message")
+  String javax_validation_constraints_DecimalMax_message();
+
+  /**
+   * Translated "must be greater than or equal to {value}".
+   *
+   * @return translated "must be greater than or equal to {value}"
+   */
+  @DefaultStringValue("must be greater than or equal to {value}")
+  @Key("javax.validation.constraints.DecimalMin.message")
+  String javax_validation_constraints_DecimalMin_message();
+
+  /**
+   * Translated "numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)".
+   *
+   * @return translated "numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)"
+   */
+  @DefaultStringValue("numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)")
+  @Key("javax.validation.constraints.Digits.message")
+  String javax_validation_constraints_Digits_message();
+
+  /**
+   * Translated "must be in the future".
+   *
+   * @return translated "must be in the future"
+   */
+  @DefaultStringValue("must be in the future")
+  @Key("javax.validation.constraints.Future.message")
+  String javax_validation_constraints_Future_message();
+
+  /**
+   * Translated "must be less than or equal to {value}".
+   *
+   * @return translated "must be less than or equal to {value}"
+   */
+  @DefaultStringValue("must be less than or equal to {value}")
+  @Key("javax.validation.constraints.Max.message")
+  String javax_validation_constraints_Max_message();
+
+  /**
+   * Translated "must be greater than or equal to {value}".
+   *
+   * @return translated "must be greater than or equal to {value}"
+   */
+  @DefaultStringValue("must be greater than or equal to {value}")
+  @Key("javax.validation.constraints.Min.message")
+  String javax_validation_constraints_Min_message();
+
+  /**
+   * Translated "may not be null".
+   *
+   * @return translated "may not be null"
+   */
+  @DefaultStringValue("may not be null")
+  @Key("javax.validation.constraints.NotNull.message")
+  String javax_validation_constraints_NotNull_message();
+
+  /**
+   * Translated "must be null".
+   *
+   * @return translated "must be null"
+   */
+  @DefaultStringValue("must be null")
+  @Key("javax.validation.constraints.Null.message")
+  String javax_validation_constraints_Null_message();
+
+  /**
+   * Translated "must be in the past".
+   *
+   * @return translated "must be in the past"
+   */
+  @DefaultStringValue("must be in the past")
+  @Key("javax.validation.constraints.Past.message")
+  String javax_validation_constraints_Past_message();
+
+  /**
+   * Translated "must match \"{regexp}\"".
+   *
+   * @return translated "must match \"{regexp}\""
+   */
+  @DefaultStringValue("must match \"{regexp}\"")
+  @Key("javax.validation.constraints.Pattern.message")
+  String javax_validation_constraints_Pattern_message();
+
+  /**
+   * Translated "size must be between {min} and {max}".
+   *
+   * @return translated "size must be between {min} and {max}"
+   */
+  @DefaultStringValue("size must be between {min} and {max}")
+  @Key("javax.validation.constraints.Size.message")
+  String javax_validation_constraints_Size_message();
+
+  /**
+   * Translated "invalid credit card number".
+   *
+   * @return translated "invalid credit card number"
+   */
+  @DefaultStringValue("invalid credit card number")
+  @Key("org.hibernate.validator.constraints.CreditCardNumber.message")
+  String org_hibernate_validator_constraints_CreditCardNumber_message();
+
+  /**
+   * Translated "not a well-formed email address".
+   *
+   * @return translated "not a well-formed email address"
+   */
+  @DefaultStringValue("not a well-formed email address")
+  @Key("org.hibernate.validator.constraints.Email.message")
+  String org_hibernate_validator_constraints_Email_message();
+
+  /**
+   * Translated "length must be between {min} and {max}".
+   *
+   * @return translated "length must be between {min} and {max}"
+   */
+  @DefaultStringValue("length must be between {min} and {max}")
+  @Key("org.hibernate.validator.constraints.Length.message")
+  String org_hibernate_validator_constraints_Length_message();
+
+  /**
+   * Translated "may not be empty".
+   *
+   * @return translated "may not be empty"
+   */
+  @DefaultStringValue("may not be empty")
+  @Key("org.hibernate.validator.constraints.NotBlank.message")
+  String org_hibernate_validator_constraints_NotBlank_message();
+
+  /**
+   * Translated "may not be empty".
+   *
+   * @return translated "may not be empty"
+   */
+  @DefaultStringValue("may not be empty")
+  @Key("org.hibernate.validator.constraints.NotEmpty.message")
+  String org_hibernate_validator_constraints_NotEmpty_message();
+
+  /**
+   * Translated "must be between {min} and {max}".
+   *
+   * @return translated "must be between {min} and {max}"
+   */
+  @DefaultStringValue("must be between {min} and {max}")
+  @Key("org.hibernate.validator.constraints.Range.message")
+  String org_hibernate_validator_constraints_Range_message();
+
+  /**
+   * Translated "script expression \"{script}\" didn't evaluate to true".
+   *
+   * @return translated "script expression \"{script}\" didn't evaluate to true"
+   */
+  @DefaultStringValue("script expression \"{script}\" didn't evaluate to true")
+  @Key("org.hibernate.validator.constraints.ScriptAssert.message")
+  String org_hibernate_validator_constraints_ScriptAssert_message();
+
+  /**
+   * Translated "must be a valid URL".
+   *
+   * @return translated "must be a valid URL"
+   */
+  @DefaultStringValue("must be a valid URL")
+  @Key("org.hibernate.validator.constraints.URL.message")
+  String org_hibernate_validator_constraints_URL_message();
+}
diff --git a/user/src/org/hibernate/validator/ValidationMessages.properties b/user/src/org/hibernate/validator/ValidationMessages.properties
new file mode 100644
index 0000000..0e92c8f
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages.properties
@@ -0,0 +1,23 @@
+
+# $Id: ValidationMessages.properties 19251 2010-04-20 15:28:18Z hardy.ferentschik $
+javax.validation.constraints.AssertFalse.message=must be false
+javax.validation.constraints.AssertTrue.message=must be true
+javax.validation.constraints.DecimalMax.message=must be less than or equal to {value}
+javax.validation.constraints.DecimalMin.message=must be greater than or equal to {value}
+javax.validation.constraints.Digits.message=numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)
+javax.validation.constraints.Future.message=must be in the future
+javax.validation.constraints.Max.message=must be less than or equal to {value}
+javax.validation.constraints.Min.message=must be greater than or equal to {value}
+javax.validation.constraints.NotNull.message=may not be null
+javax.validation.constraints.Null.message=must be null
+javax.validation.constraints.Past.message=must be in the past
+javax.validation.constraints.Pattern.message=must match "{regexp}"
+javax.validation.constraints.Size.message=size must be between {min} and {max}
+org.hibernate.validator.constraints.Email.message=not a well-formed email address
+org.hibernate.validator.constraints.Length.message=length must be between {min} and {max}
+org.hibernate.validator.constraints.NotBlank.message=may not be empty
+org.hibernate.validator.constraints.NotEmpty.message=may not be empty
+org.hibernate.validator.constraints.Range.message=must be between {min} and {max}
+org.hibernate.validator.constraints.URL.message=must be a valid URL
+org.hibernate.validator.constraints.CreditCardNumber.message=invalid credit card number
+org.hibernate.validator.constraints.ScriptAssert.message=script expression "{script}" didn't evaluate to true
diff --git a/user/src/org/hibernate/validator/ValidationMessages_de.properties b/user/src/org/hibernate/validator/ValidationMessages_de.properties
new file mode 100644
index 0000000..194b15d
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages_de.properties
@@ -0,0 +1,22 @@
+# $Id: ValidationMessages_de.properties 19251 2010-04-20 15:28:18Z hardy.ferentschik $
+javax.validation.constraints.NotNull.message=kann nicht null sein
+javax.validation.constraints.Size.message=muss zwischen {min} und {max} liegen
+javax.validation.constraints.Pattern.message=muss auf Ausdruck "{regexp}" passen
+javax.validation.constraints.Min.message=muss gr\u00F6ssergleich {value} sein
+javax.validation.constraints.Max.message=muss kleinergleich {value} sein
+javax.validation.constraints.Null.message=muss null sein
+javax.validation.constraints.Past.message=muss in der Vergangenheit liegen
+javax.validation.constraints.Future.message=muss in der Zukunft liegen
+javax.validation.constraints.AssertTrue.message=muss wahr sein
+javax.validation.constraints.AssertFalse.message=muss falsch sein
+javax.validation.constraints.Digits.message=numerischer Wert au\u00DFerhalb erlaubten Wertebereichs (<{integer} Ziffern>.<{fraction} Ziffern> erwartet)
+javax.validation.constraints.DecimalMin.message=muss gr\u00F6ssergleich {value} sein
+javax.validation.constraints.DecimalMax.message=muss kleinergleich {value} sein
+org.hibernate.validator.constraints.Email.message=keine g\u00FCltige E-Mail-Adresse
+org.hibernate.validator.constraints.Length.message=muss zwischen {min} und {max} liegen
+org.hibernate.validator.constraints.NotBlank.message=kann nicht leer sein
+org.hibernate.validator.constraints.NotEmpty.message=kann nicht leer sein
+org.hibernate.validator.constraints.Range.message=muss zwischen {min} und {max} liegen
+org.hibernate.validator.constraints.URL.message=muss eine g\u00FCltige URL sein
+org.hibernate.validator.constraints.CreditCardNumber.message=ung\u00FCltige Kreditkartennummer
+org.hibernate.validator.constraints.ScriptAssert.message=Skriptausdruck "{script}" muss true zur\u00FCckliefern
diff --git a/user/src/org/hibernate/validator/ValidationMessages_en.properties b/user/src/org/hibernate/validator/ValidationMessages_en.properties
new file mode 100644
index 0000000..cea61f0
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages_en.properties
@@ -0,0 +1,9 @@
+# $Id: ValidationMessages_en.properties 19090 2010-03-23 15:22:59Z hardy.ferentschik $
+# This file is intentionally left empty. All calls to this bundle will
+# be delegated to the parent bundle ValidationMessages (which contains 
+# English messages).
+#
+# Not providing this bundle would cause the bundle for the default 
+# locale to take precedence over the base bundle. If the default locale 
+# is not English but one, for which a resource bundle exists (e.g. German),
+# the English texts would never be returned.
diff --git a/user/src/org/hibernate/validator/ValidationMessages_fr.properties b/user/src/org/hibernate/validator/ValidationMessages_fr.properties
new file mode 100644
index 0000000..44713b5
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages_fr.properties
@@ -0,0 +1,21 @@
+# $Id: ValidationMessages_fr.properties 19252 2010-04-20 15:29:43Z hardy.ferentschik $
+javax.validation.constraints.NotNull.message=ne peut pas \u00EAtre nul
+javax.validation.constraints.Size.message=la taille doit \u00EAtre entre {min} et {max}
+javax.validation.constraints.Pattern.message=doit suivre "{regexp}"
+javax.validation.constraints.Min.message=doit \u00EAtre plus grand que {value}
+javax.validation.constraints.Max.message=doit \u00EAtre plus petit que {value}
+javax.validation.constraints.Null.message=doit \u00EAtre nul
+javax.validation.constraints.Past.message=doit \u00EAtre dans le pass\u00E9
+javax.validation.constraints.Future.message=doit \u00EAtre dans le futur
+javax.validation.constraints.AssertTrue.message=doit \u00EAtre vrai
+javax.validation.constraints.AssertFalse.message=doit \u00EAtre faux
+javax.validation.constraints.Digits.message=Valeur num\u00E9rique hors limite (<{integer} chiffres>.<{fraction} chiffres> attendus)
+javax.validation.constraints.DecimalMin.message=doit \u00EAtre plus grand que {value}
+javax.validation.constraints.DecimalMax.message=doit \u00EAtre plus petit que {value}
+org.hibernate.validator.constraints.Email.message=Addresse email mal form\u00E9e
+org.hibernate.validator.constraints.Length.message=la taille doit \u00EAtre entre {min} et {max}
+org.hibernate.validator.constraints.NotBlank.message=ne peut pas \u00EAtre vide
+org.hibernate.validator.constraints.NotEmpty.message=ne peut pas \u00EAtre vide
+org.hibernate.validator.constraints.Range.message=doit \u00EAtre entre {min} et {max}
+org.hibernate.validator.constraints.URL.message=URL mal form\u00E9e
+org.hibernate.validator.constraints.CreditCardNumber.message=Num\u00E9ro de carte de cr\u00E9dit invalide
\ No newline at end of file
diff --git a/user/src/org/hibernate/validator/ValidationMessages_mn_MN.properties b/user/src/org/hibernate/validator/ValidationMessages_mn_MN.properties
new file mode 100644
index 0000000..f11da6f
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages_mn_MN.properties
@@ -0,0 +1,18 @@
+javax.validation.constraints.AssertFalse.message=\u0425\u0443\u0434\u0430\u043B \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.AssertTrue.message=\u04AE\u043D\u044D\u043D \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.DecimalMax.message={value}-\u0430\u0430\u0441 \u0431\u0430\u0433\u0430 \u0431\u0443\u044E\u0443 \u0442\u044D\u043D\u0446\u04AF\u04AF \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.DecimalMin.message={value}-\u0430\u0430\u0441 \u0438\u0445 \u0431\u0443\u044E\u0443 \u0442\u044D\u043D\u0446\u04AF\u04AF \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Digits.message=\u0422\u043E\u043E\u043D \u0445\u044F\u0437\u0433\u0430\u0430\u0440\u0430\u0430\u0441 \u0445\u044D\u0442\u044D\u0440\u0441\u044D\u043D \u0431\u0430\u0439\u043D\u0430 (<{integerDigits} digits>.<{fractionalDigits} digits> \u0445\u043E\u043E\u0440\u043E\u043D\u0434 \u0431\u0430\u0439\u043D\u0430)
+javax.validation.constraints.Future.message=\u0418\u0440\u044D\u044D\u0434\u04AF\u0439\u0434 \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Max.message={value}-\u0430\u0430\u0441 \u0431\u0430\u0433\u0430 \u0431\u0443\u044E\u0443 \u0442\u044D\u043D\u0446\u04AF\u04AF \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Min.message={value}-\u0430\u0430\u0441 \u0438\u0445 \u0431\u0443\u044E\u0443 \u0442\u044D\u043D\u0446\u04AF\u04AF \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.NotNull.message=null \u0431\u0430\u0439\u0436 \u0431\u043E\u043B\u043E\u0445\u0433\u04AF\u0439
+javax.validation.constraints.Null.message=null \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Past.message=\u04E8\u043D\u0433\u04E9\u0440\u0441\u04E9\u043D\u0434 \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Pattern.message=\"{regexp}\"-\u0434 \u0442\u0430\u0430\u0440\u0430\u0445 \u0451\u0441\u0442\u043E\u0439
+javax.validation.constraints.Size.message=\u0425\u044D\u043C\u0436\u044D\u044D {min}-\u0441 {max} \u0445\u043E\u043E\u0440\u043E\u043D\u0434 \u0431\u0430\u0439\u043D\u0430
+org.hibernate.validator.constraints.Email.message=\u0411\u0443\u0440\u0443\u0443 \u0438-\u043C\u044D\u0439\u043B \u0445\u0430\u044F\u0433 \u0431\u0430\u0439\u043D\u0430
+org.hibernate.validator.constraints.Length.message=\u0422\u044D\u043C\u0434\u044D\u0433\u0442\u0438\u0439\u043D \u0443\u0440\u0442 {min}-\u0441 {max} \u0445\u043E\u043E\u0440\u043E\u043D\u0434 \u0431\u0430\u0439\u043D\u0430
+org.hibernate.validator.constraints.NotBlank.message=\u0425\u043E\u043E\u0441\u043E\u043D \u0431\u0430\u0439\u0436 \u0431\u043E\u043B\u043E\u0445\u0433\u04AF\u0439
+org.hibernate.validator.constraints.NotEmpty.message=\u0425\u043E\u043E\u0441\u043E\u043D \u0431\u0430\u0439\u0436 \u0431\u043E\u043B\u043E\u0445\u0433\u04AF\u0439
+org.hibernate.validator.constraints.Range.message=\u0423\u0442\u0433\u0430 {min}-\u0441 {max} \u0445\u043E\u043E\u0440\u043E\u043D\u0434 \u0431\u0430\u0439\u043D\u0430
\ No newline at end of file
diff --git a/user/src/org/hibernate/validator/ValidationMessages_tr.properties b/user/src/org/hibernate/validator/ValidationMessages_tr.properties
new file mode 100644
index 0000000..01acd7f
--- /dev/null
+++ b/user/src/org/hibernate/validator/ValidationMessages_tr.properties
@@ -0,0 +1,18 @@
+javax.validation.constraints.AssertFalse.message=teyit ba\u015far\u0131s\u0131z
+javax.validation.constraints.AssertTrue.message=teyit ba\u015far\u0131s\u0131z
+javax.validation.constraints.DecimalMax.message='{value}' de\u011ferinden k\u00fc\u00e7\u00fck yada e\u015fit olmal\u0131
+javax.validation.constraints.DecimalMin.message='{value}' de\u011ferinden b\u00fcy\u00fck yada e\u015fit olmal\u0131
+javax.validation.constraints.Digits.message=s\u0131n\u0131rlar\u0131n d\u0131\u015f\u0131nda say\u0131sal de\u011fer (beklenen <{integerDigits} basamak>.<{fractionalDigits} basamak>)
+javax.validation.constraints.Future.message=ileri bir tarih olmal\u0131
+javax.validation.constraints.Max.message='{value}' de\u011ferinden k\u00fc\u00e7\u00fck yada e\u015fit olmal\u0131
+javax.validation.constraints.Min.message='{value}' de\u011ferinden b\u00fcy\u00fck yada e\u015fit olmal\u0131
+javax.validation.constraints.NotNull.message=bo\u015f de\u011fer olamaz
+javax.validation.constraints.Null.message=bo\u015f de\u011fer olmal\u0131
+javax.validation.constraints.Past.message=ge\u00e7mi\u015f bir tarih olmal\u0131
+javax.validation.constraints.Pattern.message='{regexp}' ile e\u015fle\u015fmeli
+javax.validation.constraints.Size.message=boyut '{min}' ile '{max}' aras\u0131nda olmal\u0131
+org.hibernate.validator.constraints.Length.message=uzunluk '{min}' ile '{max}' aras\u0131nda olmal\u0131
+org.hibernate.validator.constraints.NotBlank.message=bo\u015f de\u011fer olamaz
+org.hibernate.validator.constraints.NotEmpty.message=bo\u015f de\u011fer olamaz
+org.hibernate.validator.constraints.Email.message=d\u00fczg\u00fcn bi\u00e7imli bir e-posta adresi de\u011fil!
+org.hibernate.validator.constraints.Range.message={min} ve {max} aras\u0131nda olmal\u0131d\u0131r!
diff --git a/user/test/com/google/gwt/validation/client/constraints/ConstraintsGwtSuite.java b/user/test/com/google/gwt/validation/ConstraintsGwtSuite.java
similarity index 90%
rename from user/test/com/google/gwt/validation/client/constraints/ConstraintsGwtSuite.java
rename to user/test/com/google/gwt/validation/ConstraintsGwtSuite.java
index 45ca523..2930f06 100644
--- a/user/test/com/google/gwt/validation/client/constraints/ConstraintsGwtSuite.java
+++ b/user/test/com/google/gwt/validation/ConstraintsGwtSuite.java
@@ -13,9 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.validation.client.constraints;
+package com.google.gwt.validation;
 
 import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.validation.client.constraints.GwtCompileTest;
 
 import junit.framework.Test;
 
diff --git a/user/test/com/google/gwt/validation/ConstraintsJreSuite.java b/user/test/com/google/gwt/validation/ConstraintsJreSuite.java
new file mode 100644
index 0000000..218e53f
--- /dev/null
+++ b/user/test/com/google/gwt/validation/ConstraintsJreSuite.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import com.google.gwt.validation.client.constraints.AssertFalseValidatorTest;
+import com.google.gwt.validation.client.constraints.AssertTrueValidatorTest;
+import com.google.gwt.validation.client.constraints.DecimalMaxValidatorForNumberTest;
+import com.google.gwt.validation.client.constraints.DecimalMaxValidatorForStringTest;
+import com.google.gwt.validation.client.constraints.DecimalMinValidatorForNumberTest;
+import com.google.gwt.validation.client.constraints.DecimalMinValidatorForStringTest;
+import com.google.gwt.validation.client.constraints.DigitsValidatorForNumberTest;
+import com.google.gwt.validation.client.constraints.DigitsValidatorForStringTest;
+import com.google.gwt.validation.client.constraints.FutureValidatorForDateTest;
+import com.google.gwt.validation.client.constraints.MaxValidatorForNumberTest;
+import com.google.gwt.validation.client.constraints.MaxValidatorForStringTest;
+import com.google.gwt.validation.client.constraints.MinValidatorForNumberTest;
+import com.google.gwt.validation.client.constraints.MinValidatorForStringTest;
+import com.google.gwt.validation.client.constraints.NotNullValidatorTest;
+import com.google.gwt.validation.client.constraints.NullValidatorTest;
+import com.google.gwt.validation.client.constraints.PastValidatorForDateTest;
+import com.google.gwt.validation.client.constraints.PatternValidatorTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfBooleanTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfByteTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfCharTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfDoubleTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfFloatTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfIntTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfLongTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfObjectTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForArrayOfShortTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForCollectionTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForMapTest;
+import com.google.gwt.validation.client.constraints.SizeValidatorForStringTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * All Constraints tests that don't need GWTTestCase.
+ */
+public class ConstraintsJreSuite {
+  public static Test suite() {
+    TestSuite suite = new TestSuite(
+        "Validation Constraint tests that require the JRE");
+    suite.addTestSuite(AssertFalseValidatorTest.class);
+    suite.addTestSuite(AssertTrueValidatorTest.class);
+    suite.addTestSuite(DecimalMaxValidatorForNumberTest.class);
+    suite.addTestSuite(DecimalMaxValidatorForStringTest.class);
+    suite.addTestSuite(DecimalMinValidatorForNumberTest.class);
+    suite.addTestSuite(DecimalMinValidatorForStringTest.class);
+    suite.addTestSuite(DigitsValidatorForNumberTest.class);
+    suite.addTestSuite(DigitsValidatorForStringTest.class);
+    suite.addTestSuite(FutureValidatorForDateTest.class);
+    suite.addTestSuite(MaxValidatorForNumberTest.class);
+    suite.addTestSuite(MaxValidatorForStringTest.class);
+    suite.addTestSuite(MinValidatorForNumberTest.class);
+    suite.addTestSuite(MinValidatorForStringTest.class);
+    suite.addTestSuite(NotNullValidatorTest.class);
+    suite.addTestSuite(NullValidatorTest.class);
+    suite.addTestSuite(PastValidatorForDateTest.class);
+    suite.addTestSuite(PatternValidatorTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfBooleanTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfByteTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfCharTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfDoubleTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfFloatTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfIntTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfLongTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfObjectTest.class);
+    suite.addTestSuite(SizeValidatorForArrayOfShortTest.class);
+    suite.addTestSuite(SizeValidatorForCollectionTest.class);
+    suite.addTestSuite(SizeValidatorForMapTest.class);
+    suite.addTestSuite(SizeValidatorForCollectionTest.class);
+    suite.addTestSuite(SizeValidatorForMapTest.class);
+    suite.addTestSuite(SizeValidatorForStringTest.class);
+    return suite;
+  }
+}
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/test/com/google/gwt/validation/ValidationClientGwtSuite.java
similarity index 81%
rename from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
rename to user/test/com/google/gwt/validation/ValidationClientGwtSuite.java
index 03e87ad..a40bd79 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/test/com/google/gwt/validation/ValidationClientGwtSuite.java
@@ -13,9 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.validation.client;
+package com.google.gwt.validation;
 
 import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.validation.client.BaseMessageInterpolatorTest;
+import com.google.gwt.validation.client.SimpleSampleTest;
 
 import junit.framework.Test;
 
@@ -27,6 +29,7 @@
   public static Test suite() {
     GWTTestSuite suite = new GWTTestSuite(
         "Test suite for all validation code.");
+    suite.addTestSuite(BaseMessageInterpolatorTest.class);
     suite.addTestSuite(SimpleSampleTest.class);
     return suite;
   }
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientJreSuite.java b/user/test/com/google/gwt/validation/ValidationClientJreSuite.java
similarity index 96%
rename from user/test/com/google/gwt/validation/client/ValidationClientJreSuite.java
rename to user/test/com/google/gwt/validation/ValidationClientJreSuite.java
index ec75ece..bc794e7 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientJreSuite.java
+++ b/user/test/com/google/gwt/validation/ValidationClientJreSuite.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.validation.client;
+package com.google.gwt.validation;
 
 import com.google.gwt.validation.client.impl.NodeImplTest;
 import com.google.gwt.validation.client.impl.PathImplTest;
diff --git a/user/test/com/google/gwt/validation/ValidationTest.gwt.xml b/user/test/com/google/gwt/validation/ValidationTest.gwt.xml
new file mode 100644
index 0000000..d088c8f
--- /dev/null
+++ b/user/test/com/google/gwt/validation/ValidationTest.gwt.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.1/distro-source/core/src/gwt-module.dtd">
+<!--
+  Copyright 2010 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License. You may obtain a copy of
+  the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+  License for the specific language governing permissions and limitations under
+  the License.
+-->
+<module>
+  <inherits name="com.google.gwt.user.User" />
+  <inherits name="org.hibernate.validator.HibernateValidator" />
+  <source path="client">
+  </source>
+</module>
\ No newline at end of file
diff --git a/user/test/com/google/gwt/validation/client/BaseMessageInterpolatorTest.java b/user/test/com/google/gwt/validation/client/BaseMessageInterpolatorTest.java
new file mode 100644
index 0000000..5b8a2f3
--- /dev/null
+++ b/user/test/com/google/gwt/validation/client/BaseMessageInterpolatorTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test for {@link BaseMessageInterpolator}. Full tests are in the TCK.
+ */
+public class BaseMessageInterpolatorTest extends ValidationClientGwtTestCase {
+  BaseMessageInterpolator interpolator;
+  Map<String, Object> defaultMap = new HashMap<String, Object>();
+
+  public void testReplace_foo() {
+    assertAttributesReplaced("bar", "{foo}", defaultMap);
+  }
+
+  public void testReplace_fooFoo() {
+    assertAttributesReplaced("bar and bar", "{foo} and {foo}", defaultMap);
+  }
+
+  public void testReplace_integer() {
+    assertAttributesReplaced("integer=1", "integer={integer}", defaultMap);
+  }
+
+  public void testReplace_none() {
+    assertAttributesReplaced("none", "none", defaultMap);
+  }
+
+  protected void assertAttributesReplaced(String expected, String message,
+      Map<String, Object> map) {
+    String result = interpolator.replaceParameters(message,
+        BaseMessageInterpolator.createAnnotationReplacer(map));
+    assertEquals(expected, result);
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    super.gwtSetUp();
+    interpolator = new GwtMessageInterpolator();
+    defaultMap.clear();
+    defaultMap.put("foo", "bar");
+    defaultMap.put("integer", Integer.valueOf(1));
+  }
+}
diff --git a/user/test/com/google/gwt/validation/client/SimpleSampleTest.java b/user/test/com/google/gwt/validation/client/SimpleSampleTest.java
index 37d3661..72c6860 100644
--- a/user/test/com/google/gwt/validation/client/SimpleSampleTest.java
+++ b/user/test/com/google/gwt/validation/client/SimpleSampleTest.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.validation.client.impl.ConstraintViolationImpl;
 
 import javax.validation.ConstraintViolation;
@@ -24,14 +23,9 @@
 /**
  * Tests for {@link SimpleSample}.
  */
-public class SimpleSampleTest extends GWTTestCase {
+public class SimpleSampleTest extends ValidationClientGwtTestCase {
   SimpleSample sample;
 
-  @Override
-  protected void gwtSetUp() {
-    sample = new SimpleSample();
-  }
-
   public void testAnnotatedClassCompiles() throws Exception {
     // Only tests that validation annotated class compile
     assertEquals(null, sample.getName());
@@ -47,7 +41,7 @@
   }
 
   @Override
-  public String getModuleName() {
-    return "com.google.gwt.validation.Validation";
+  protected void gwtSetUp() {
+    sample = new SimpleSample();
   }
 }
diff --git a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java b/user/test/com/google/gwt/validation/client/ValidationClientGwtTestCase.java
similarity index 65%
copy from user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
copy to user/test/com/google/gwt/validation/client/ValidationClientGwtTestCase.java
index 03e87ad..eb2d781 100644
--- a/user/test/com/google/gwt/validation/client/ValidationClientGwtSuite.java
+++ b/user/test/com/google/gwt/validation/client/ValidationClientGwtTestCase.java
@@ -15,19 +15,15 @@
  */
 package com.google.gwt.validation.client;
 
-import com.google.gwt.junit.tools.GWTTestSuite;
-
-import junit.framework.Test;
+import com.google.gwt.junit.client.GWTTestCase;
 
 /**
- * All validation client GWT tests.
+ * Base {@link GWTTestCase} for Validation Client tests.
  */
-public class ValidationClientGwtSuite {
+public abstract class ValidationClientGwtTestCase extends GWTTestCase {
 
-  public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test suite for all validation code.");
-    suite.addTestSuite(SimpleSampleTest.class);
-    return suite;
+  @Override
+  public final String getModuleName() {
+    return "com.google.gwt.validation.ValidationTest";
   }
-}
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/validation/client/constraints/ConstraintsJreSuite.java b/user/test/com/google/gwt/validation/client/constraints/ConstraintsJreSuite.java
deleted file mode 100644
index 98f1a38..0000000
--- a/user/test/com/google/gwt/validation/client/constraints/ConstraintsJreSuite.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.constraints;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * All Constraints tests that don't need GWTTestCase.
- */
-public class ConstraintsJreSuite {
-  public static Test suite() {
-    TestSuite suite = new TestSuite(
-        "Validation Constraint tests that require the JRE");
-    suite.addTestSuite(AssertFalseValidatorTest.class);
-    suite.addTestSuite(AssertTrueValidatorTest.class);
-    suite.addTestSuite(DecimalMaxValidatorForNumberTest.class);
-    suite.addTestSuite(DecimalMaxValidatorForStringTest.class);
-    suite.addTestSuite(DecimalMinValidatorForNumberTest.class);
-    suite.addTestSuite(DecimalMinValidatorForStringTest.class);
-    suite.addTestSuite(DigitsValidatorForNumberTest.class);
-    suite.addTestSuite(DigitsValidatorForStringTest.class);
-    suite.addTestSuite(FutureValidatorForDateTest.class);
-    suite.addTestSuite(MaxValidatorForNumberTest.class);
-    suite.addTestSuite(MaxValidatorForStringTest.class);
-    suite.addTestSuite(MinValidatorForNumberTest.class);
-    suite.addTestSuite(MinValidatorForStringTest.class);
-    suite.addTestSuite(NotNullValidatorTest.class);
-    suite.addTestSuite(NullValidatorTest.class);
-    suite.addTestSuite(PastValidatorForDateTest.class);
-    suite.addTestSuite(PatternValidatorTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfBooleanTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfByteTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfCharTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfDoubleTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfFloatTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfIntTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfLongTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfObjectTest.class);
-    suite.addTestSuite(SizeValidatorForArrayOfShortTest.class);
-    suite.addTestSuite(SizeValidatorForCollectionTest.class);
-    suite.addTestSuite(SizeValidatorForMapTest.class);
-    suite.addTestSuite(SizeValidatorForCollectionTest.class);
-    suite.addTestSuite(SizeValidatorForMapTest.class);
-    suite.addTestSuite(SizeValidatorForStringTest.class);
-    return suite;
-  }
-}
diff --git a/user/test/com/google/gwt/validation/client/constraints/GwtCompileTest.java b/user/test/com/google/gwt/validation/client/constraints/GwtCompileTest.java
index b031395..29d193e 100644
--- a/user/test/com/google/gwt/validation/client/constraints/GwtCompileTest.java
+++ b/user/test/com/google/gwt/validation/client/constraints/GwtCompileTest.java
@@ -1,12 +1,12 @@
 /*
  * 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
@@ -15,7 +15,7 @@
  */
 package com.google.gwt.validation.client.constraints;
 
-import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.validation.client.ValidationClientGwtTestCase;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -24,12 +24,7 @@
  * A GWT test to force the compilation of all default standard
  * {@link javax.validation.ConstraintValidator}s.
  */
-public class GwtCompileTest extends GWTTestCase {
-
-  @Override
-  public String getModuleName() {
-    return "com.google.gwt.validation.Validation";
-  }
+public class GwtCompileTest extends ValidationClientGwtTestCase {
 
   public void testDefaultConstraints() {
     List<Class<?>> temp = new ArrayList<Class<?>>();
diff --git a/user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java b/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
similarity index 90%
rename from user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java
rename to user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
index e9a711a..c13ee78 100644
--- a/user/test/com/google/gwt/validation/example/client/ExampleValidationClientGwtSuite.java
+++ b/user/test/com/google/gwt/validation/example/ExampleValidationClientGwtSuite.java
@@ -13,9 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.validation.example.client;
+package com.google.gwt.validation.example;
 
 import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.validation.example.client.AuthorTest;
 
 import junit.framework.Test;
 
diff --git a/user/test/com/google/gwt/validation/example/ValidationExample.gwt.xml b/user/test/com/google/gwt/validation/example/ValidationExample.gwt.xml
index a659123..a719210 100644
--- a/user/test/com/google/gwt/validation/example/ValidationExample.gwt.xml
+++ b/user/test/com/google/gwt/validation/example/ValidationExample.gwt.xml
@@ -18,5 +18,10 @@
 <module>
   <inherits name="com.google.gwt.user.User" />
   <inherits name="org.hibernate.validator.HibernateValidator" />
-  <source path="client" />
+  <source path="client">
+  </source>
+  <replace-with
+    class="com.google.gwt.validation.example.client.ExampleValidatorFactory">
+    <when-type-is class="javax.validation.ValidatorFactory" />
+</replace-with>
 </module>
\ No newline at end of file
diff --git a/user/test/com/google/gwt/validation/example/client/AuthorTest.java b/user/test/com/google/gwt/validation/example/client/AuthorTest.java
index 9450609..374399d 100644
--- a/user/test/com/google/gwt/validation/example/client/AuthorTest.java
+++ b/user/test/com/google/gwt/validation/example/client/AuthorTest.java
@@ -15,10 +15,9 @@
  */
 package com.google.gwt.validation.example.client;
 
-import com.google.gwt.core.client.GWT;
 import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.validation.example.client.ExampleGwtValidator.ClientGroup;
-import com.google.gwt.validation.example.client.ExampleGwtValidator.ServerGroup;
+import com.google.gwt.validation.example.client.ExampleValidatorFactory.ClientGroup;
+import com.google.gwt.validation.example.client.ExampleValidatorFactory.ServerGroup;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -26,6 +25,7 @@
 import java.util.Set;
 
 import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
 import javax.validation.Validator;
 import javax.validation.groups.Default;
 
@@ -43,22 +43,10 @@
     return "com.google.gwt.validation.example.ValidationExample";
   }
 
-  // TODO(nchalko) handle more than one validator
-
-  // @GwtValidation(value = Author.class, groups =
-  // {ExampleGwtValidator.ClientGroup.class})
-  // public interface NotDefaultValidator extends Validator {
-  // }
-
-  // public void testNotDefaultValidtor_EmptyNotDefualt() throws Exception {
-  // NotDefaultValidator other = GWT.create(NotDefaultValidator.class);
-  // Set<ConstraintViolation<Author>> violations = other.validate(author);
-  // assertContentsAnyOrder("valid author", violations);
-  // }
-
-  public void testGroup_empty() throws Exception {
+  public void testGroup_clientGroup() throws Exception {
     initValidAuthor();
-    Set<ConstraintViolation<Author>> violations = validator.validate(author);
+    Set<ConstraintViolation<Author>> violations = validator.validate(author,
+        ClientGroup.class);
     assertContentsAnyOrder("valid author", violations);
   }
 
@@ -69,10 +57,9 @@
     assertContentsAnyOrder("valid author", violations);
   }
 
-  public void testGroup_clientGroup() throws Exception {
+  public void testGroup_empty() throws Exception {
     initValidAuthor();
-    Set<ConstraintViolation<Author>> violations = validator.validate(author,
-        ClientGroup.class);
+    Set<ConstraintViolation<Author>> violations = validator.validate(author);
     assertContentsAnyOrder("valid author", violations);
   }
 
@@ -86,6 +73,15 @@
     }
   }
 
+  public void testValidate_companySize31() {
+    initValidAuthor();
+    author.setCompany("1234567890123456789012345678901");
+    Set<ConstraintViolation<Author>> violations = validator.validate(author);
+    assertContentsAnyOrder("company size 31", toMessage(violations),
+        "size must be between 0 and 30"
+        );
+  }
+
   public void testValidate_string() {
     try {
       validator.validate("some string");
@@ -100,21 +96,6 @@
     assertContentsAnyOrder("valid author", violations);
   }
 
-  public void testValidate_companySize31() {
-    initValidAuthor();
-    author.setCompany("1234567890123456789012345678901");
-    Set<ConstraintViolation<Author>> violations = validator.validate(author);
-    assertContentsAnyOrder("company size 31", toMessage(violations),
-        "{javax.validation.constraints.Size.message}"
-        );
-  }
-
-  protected void initValidAuthor() {
-    author.setFirstName("John");
-    author.setLastName("Smith");
-    author.setCompany("Google");
-  }
-
   public void testValidateProperty_object() {
     try {
       validator.validateProperty(new Object(), "foo");
@@ -131,23 +112,17 @@
     }
   }
 
-  protected Validator createValidator() {
-    return GWT.create(ExampleGwtValidator.class);
-  }
-
   @Override
   protected final void gwtSetUp() throws Exception {
     super.gwtSetUp();
     author = new Author();
-    validator = createValidator();
+    validator = Validation.buildDefaultValidatorFactory().getValidator();
   }
-  
-  private <T> List<String> toMessage(Set<ConstraintViolation<T>> violations) {
-    List<String> messages = new ArrayList<String>();
-    for (ConstraintViolation<T> violation : violations) {
-      messages.add(violation.getMessage());
-    }
-    return messages;
+
+  protected void initValidAuthor() {
+    author.setFirstName("John");
+    author.setLastName("Smith");
+    author.setCompany("Google");
   }
 
   private <T> void assertContentsAnyOrder(String message,
@@ -166,4 +141,12 @@
       fail(message);
     }
   }
+
+  private <T> List<String> toMessage(Set<ConstraintViolation<T>> violations) {
+    List<String> messages = new ArrayList<String>();
+    for (ConstraintViolation<T> violation : violations) {
+      messages.add(violation.getMessage());
+    }
+    return messages;
+  }
 }
diff --git a/user/test/com/google/gwt/validation/example/client/ExampleGwtValidator.java b/user/test/com/google/gwt/validation/example/client/ExampleGwtValidator.java
deleted file mode 100644
index 82d79d6..0000000
--- a/user/test/com/google/gwt/validation/example/client/ExampleGwtValidator.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.example.client;
-
-import com.google.gwt.validation.client.GwtValidation;
-import com.google.gwt.validation.example.client.ExampleGwtValidator.ClientGroup;
-
-import javax.validation.Validator;
-import javax.validation.groups.Default;
-
-/**
- * Example top level class to create a {@link Validator}.
- *
- * GWT.create instances of this class
- */
-@GwtValidation(
-    value = {Author.class}, 
-    groups = {Default.class, ClientGroup.class})
-public interface ExampleGwtValidator extends Validator {
-  /**
-   * The Client Validation Group
-   */
-  public interface ClientGroup {
-  }
-
-  /**
-   * The Server Validation Group
-   */
-  public interface ServerGroup {
-  }
-}
diff --git a/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java b/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java
new file mode 100644
index 0000000..05f1a70
--- /dev/null
+++ b/user/test/com/google/gwt/validation/example/client/ExampleValidatorFactory.java
@@ -0,0 +1,59 @@
+/*
+ * 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.example.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
+
+import javax.validation.Validator;
+import javax.validation.groups.Default;
+
+/**
+ * Factory to create the Validator specified by {@link GwtValidator}.
+ *
+ * GWT.create instances of this class
+ */
+public class ExampleValidatorFactory extends AbstractGwtValidatorFactory {
+
+  /**
+   * Marks constraints that should run on the client.
+   */
+  public interface ClientGroup {
+  }
+
+  /**
+   * Validator Interface annotated with the list of classes to validate on the
+   * client.
+   */
+  @GwtValidation(
+      value = {Author.class},
+      groups = {Default.class, ClientGroup.class})
+  public interface GwtValidator extends Validator {
+  }
+
+  /**
+   * Marks constraints that should run on the server.
+   */
+  public interface ServerGroup {
+  }
+
+  @Override
+  public AbstractGwtValidator createValidator() {
+    return GWT.create(GwtValidator.class);
+  }
+}