Move AutoBean package to com.google.web.bindery.autobean package.
http://code.google.com/p/google-web-toolkit/issues/detail?id=6253
Review at http://gwt-code-reviews.appspot.com/1414803
Patch by: bobv
Review by: rjrjr


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10007 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/test/com/google/web/bindery/autobean/AutoBeanSuite.java b/user/test/com/google/web/bindery/autobean/AutoBeanSuite.java
new file mode 100644
index 0000000..387dc9d
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/AutoBeanSuite.java
@@ -0,0 +1,43 @@
+/*
+ * 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.web.bindery.autobean;
+
+import com.google.web.bindery.autobean.gwt.client.AutoBeanTest;
+import com.google.web.bindery.autobean.shared.AutoBeanCodexTest;
+import com.google.web.bindery.autobean.shared.SplittableTest;
+import com.google.web.bindery.autobean.vm.AutoBeanCodexJreTest;
+import com.google.web.bindery.autobean.vm.AutoBeanJreTest;
+import com.google.web.bindery.autobean.vm.SplittableJreTest;
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * Tests of the Editor framework. These tests focus on core Editor behaviors,
+ * rather than on integration with backing stores.
+ */
+public class AutoBeanSuite {
+  public static Test suite() {
+    GWTTestSuite suite = new GWTTestSuite("Test suite for AutoBean functions");
+    suite.addTestSuite(AutoBeanCodexJreTest.class);
+    suite.addTestSuite(AutoBeanCodexTest.class);
+    suite.addTestSuite(AutoBeanJreTest.class);
+    suite.addTestSuite(AutoBeanTest.class);
+    suite.addTestSuite(SplittableJreTest.class);
+    suite.addTestSuite(SplittableTest.class);
+    return suite;
+  }
+}
diff --git a/user/test/com/google/web/bindery/autobean/gwt/client/AutoBeanTest.java b/user/test/com/google/web/bindery/autobean/gwt/client/AutoBeanTest.java
new file mode 100644
index 0000000..3124590
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/gwt/client/AutoBeanTest.java
@@ -0,0 +1,568 @@
+/*
+ * 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.web.bindery.autobean.gwt.client;
+
+import com.google.web.bindery.autobean.shared.AutoBean;
+import com.google.web.bindery.autobean.shared.AutoBeanFactory;
+import com.google.web.bindery.autobean.shared.AutoBeanFactory.Category;
+import com.google.web.bindery.autobean.shared.AutoBeanUtils;
+import com.google.web.bindery.autobean.shared.AutoBeanVisitor;
+import com.google.web.bindery.autobean.shared.AutoBeanVisitor.ParameterizationVisitor;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Tests runtime behavior of AutoBean framework.
+ */
+public class AutoBeanTest extends GWTTestCase {
+
+  /**
+   * Static implementation of {@link HasCall}.
+   */
+  public static class CallImpl {
+    public static Object seen;
+
+    public static <T> T __intercept(AutoBean<HasCall> bean, T value) {
+      seen = value;
+      return value;
+    }
+
+    public static int add(AutoBean<HasCall> bean, int a, int b) {
+      assertNotNull(bean);
+      return ((Integer) bean.getTag("offset")) + a + b;
+    }
+  }
+
+  /**
+   * The factory being tested.
+   */
+  @Category(CallImpl.class)
+  protected interface Factory extends AutoBeanFactory {
+    AutoBean<HasBoolean> hasBoolean();
+
+    AutoBean<HasCall> hasCall();
+
+    AutoBean<HasChainedSetters> hasChainedSetters();
+
+    AutoBean<HasList> hasList();
+
+    AutoBean<HasComplexTypes> hasListOfList();
+
+    AutoBean<HasMoreChainedSetters> hasMoreChainedSetters();
+
+    AutoBean<Intf> intf();
+
+    AutoBean<Intf> intf(RealIntf wrapped);
+
+    AutoBean<OtherIntf> otherIntf();
+  }
+
+  interface HasBoolean {
+    boolean getGet();
+
+    boolean hasHas();
+
+    boolean isIs();
+
+    void setGet(boolean value);
+
+    void setHas(boolean value);
+
+    void setIs(boolean value);
+  }
+
+  interface HasCall {
+    int add(int a, int b);
+  }
+
+  interface HasChainedSetters {
+    int getInt();
+
+    String getString();
+
+    HasChainedSetters setInt(int value);
+
+    HasChainedSetters setString(String value);
+  }
+
+  interface HasComplexTypes {
+    List<List<Intf>> getList();
+
+    List<Map<String, Intf>> getListOfMap();
+
+    Map<Map<String, String>, List<List<Intf>>> getMap();
+  }
+
+  interface HasList {
+    List<Intf> getList();
+
+    void setList(List<Intf> list);
+  }
+
+  interface HasMoreChainedSetters extends HasChainedSetters {
+    boolean isBoolean();
+
+    HasMoreChainedSetters setBoolean(boolean value);
+
+    HasMoreChainedSetters setInt(int value);
+  }
+
+  interface Intf {
+    int getInt();
+
+    String getString();
+
+    void setInt(int number);
+
+    void setString(String value);
+  }
+
+  interface OtherIntf {
+    HasBoolean getHasBoolean();
+
+    Intf getIntf();
+
+    UnreferencedInFactory getUnreferenced();
+
+    void setHasBoolean(HasBoolean value);
+
+    void setIntf(Intf intf);
+  }
+
+  static class RealIntf implements Intf {
+    int i;
+    String string;
+
+    @Override
+    public boolean equals(Object o) {
+      return (o instanceof Intf) && (((Intf) o).getInt() == getInt());
+    }
+
+    public int getInt() {
+      return i;
+    }
+
+    public String getString() {
+      return string;
+    }
+
+    @Override
+    public int hashCode() {
+      return i;
+    }
+
+    public void setInt(int number) {
+      this.i = number;
+    }
+
+    public void setString(String value) {
+      this.string = value;
+    }
+
+    public String toString() {
+      return "toString";
+    }
+  }
+
+  interface UnreferencedInFactory {
+  }
+
+  private static class ParameterizationTester extends ParameterizationVisitor {
+    private final StringBuilder sb;
+    private Stack<Boolean> isOpen = new Stack<Boolean>();
+
+    private ParameterizationTester(StringBuilder sb) {
+      this.sb = sb;
+    }
+
+    @Override
+    public void endVisitType(Class<?> type) {
+      if (isOpen.pop()) {
+        sb.append(">");
+      }
+    }
+
+    @Override
+    public boolean visitParameter() {
+      if (isOpen.peek()) {
+        sb.append(",");
+      } else {
+        sb.append("<");
+        isOpen.pop();
+        isOpen.push(true);
+      }
+      return true;
+    }
+
+    @Override
+    public boolean visitType(Class<?> type) {
+      sb.append(type.getName());
+      isOpen.push(false);
+      return true;
+    }
+  }
+
+  protected Factory factory;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.web.bindery.autobean.AutoBean";
+  }
+
+  public void testBooleanIsHasMethods() {
+    HasBoolean b = factory.hasBoolean().as();
+    assertFalse(b.getGet());
+    assertFalse(b.hasHas());
+    assertFalse(b.isIs());
+
+    b.setGet(true);
+    b.setHas(true);
+    b.setIs(true);
+
+    assertTrue(b.getGet());
+    assertTrue(b.hasHas());
+    assertTrue(b.isIs());
+  }
+
+  public void testCategory() {
+    AutoBean<HasCall> call = factory.hasCall();
+    call.setTag("offset", 1);
+    assertEquals(6, call.as().add(2, 3));
+    assertEquals(6, CallImpl.seen);
+  }
+
+  public void testChainedSetters() {
+    AutoBean<HasChainedSetters> bean = factory.hasChainedSetters();
+    bean.as().setInt(42).setString("Blah");
+    assertEquals(42, bean.as().getInt());
+    assertEquals("Blah", bean.as().getString());
+
+    AutoBean<HasMoreChainedSetters> more = factory.hasMoreChainedSetters();
+    more.as().setInt(42).setBoolean(true).setString("Blah");
+    assertEquals(42, more.as().getInt());
+    assertTrue(more.as().isBoolean());
+    assertEquals("Blah", more.as().getString());
+  }
+
+  public void testDiff() {
+    AutoBean<Intf> a1 = factory.intf();
+    AutoBean<Intf> a2 = factory.intf();
+
+    assertTrue(AutoBeanUtils.diff(a1, a2).isEmpty());
+
+    a2.as().setInt(42);
+    Map<String, Object> diff = AutoBeanUtils.diff(a1, a2);
+    assertEquals(1, diff.size());
+    assertEquals(42, diff.get("int"));
+  }
+
+  public void testDiffWithListPropertyAssignment() {
+    AutoBean<HasList> a1 = factory.hasList();
+    AutoBean<HasList> a2 = factory.hasList();
+
+    assertTrue(AutoBeanUtils.diff(a1, a2).isEmpty());
+
+    List<Intf> l1 = new ArrayList<Intf>();
+    a1.as().setList(l1);
+    List<Intf> l2 = new ArrayList<Intf>();
+    a2.as().setList(l2);
+
+    assertTrue(AutoBeanUtils.diff(a1, a2).isEmpty());
+
+    l2.add(factory.intf().as());
+    Map<String, Object> diff = AutoBeanUtils.diff(a1, a2);
+    assertEquals(1, diff.size());
+    assertEquals(l2, diff.get("list"));
+
+    l1.add(l2.get(0));
+    assertTrue(AutoBeanUtils.diff(a1, a2).isEmpty());
+  }
+
+  public void testDynamicMethods() {
+    AutoBean<Intf> intf = factory.create(Intf.class);
+    assertNotNull(intf);
+
+    RealIntf real = new RealIntf();
+    real.i = 42;
+    intf = factory.create(Intf.class, real);
+    assertNotNull(intf);
+    assertEquals(42, intf.as().getInt());
+  }
+
+  public void testEquality() {
+    AutoBean<Intf> a1 = factory.intf();
+    AutoBean<Intf> a2 = factory.intf();
+
+    assertNotSame(a1, a2);
+    assertFalse(a1.equals(a2));
+
+    // Make sure as() is stable
+    assertSame(a1.as(), a1.as());
+    assertEquals(a1.as(), a1.as());
+
+    // When wrapping, use underlying object's equality
+    RealIntf real = new RealIntf();
+    real.i = 42;
+    AutoBean<Intf> w = factory.intf(real);
+    // AutoBean interface never equals wrapped object
+    assertFalse(w.equals(real));
+    // Wrapper interface should delegate hashCode(), equals(), and toString()
+    assertEquals(real.hashCode(), w.as().hashCode());
+    assertEquals(real, w.as());
+    assertEquals(real.toString(), w.as().toString());
+    assertEquals(w.as(), real);
+  }
+
+  public void testFactory() {
+    AutoBean<Intf> auto = factory.intf();
+    assertSame(factory, auto.getFactory());
+  }
+
+  public void testFreezing() {
+    AutoBean<Intf> auto = factory.intf();
+    Intf intf = auto.as();
+    intf.setInt(42);
+    auto.setFrozen(true);
+    try {
+      intf.setInt(55);
+      fail("Should have thrown an exception");
+    } catch (IllegalStateException expected) {
+    }
+
+    assertTrue(auto.isFrozen());
+    assertEquals(42, intf.getInt());
+  }
+
+  public void testNested() {
+    AutoBean<OtherIntf> auto = factory.otherIntf();
+    OtherIntf other = auto.as();
+
+    assertNull(other.getIntf());
+
+    Intf intf = new RealIntf();
+    intf.setString("Hello world!");
+    other.setIntf(intf);
+    Intf retrieved = other.getIntf();
+    assertEquals("Hello world!", retrieved.getString());
+    assertNotNull(AutoBeanUtils.getAutoBean(retrieved));
+  }
+
+  public void testParameterizationVisitor() {
+    AutoBean<HasComplexTypes> auto = factory.hasListOfList();
+    auto.accept(new AutoBeanVisitor() {
+      int count = 0;
+
+      @Override
+      public void endVisit(AutoBean<?> bean, Context ctx) {
+        assertEquals(3, count);
+      }
+
+      @Override
+      public void endVisitCollectionProperty(String propertyName, AutoBean<Collection<?>> value,
+          CollectionPropertyContext ctx) {
+        check(propertyName, ctx);
+      }
+
+      @Override
+      public void endVisitMapProperty(String propertyName, AutoBean<Map<?, ?>> value,
+          MapPropertyContext ctx) {
+        check(propertyName, ctx);
+      }
+
+      private void check(String propertyName, PropertyContext ctx) {
+        count++;
+        StringBuilder sb = new StringBuilder();
+        ctx.accept(new ParameterizationTester(sb));
+
+        if ("list".equals(propertyName)) {
+          // List<List<Intf>>
+          assertEquals(List.class.getName() + "<" + List.class.getName() + "<"
+              + Intf.class.getName() + ">>", sb.toString());
+        } else if ("listOfMap".equals(propertyName)) {
+          // List<Map<String, Intf>>
+          assertEquals(List.class.getName() + "<" + Map.class.getName() + "<"
+              + String.class.getName() + "," + Intf.class.getName() + ">>", sb.toString());
+        } else if ("map".equals(propertyName)) {
+          // Map<Map<String, String>, List<List<Intf>>>
+          assertEquals(Map.class.getName() + "<" + Map.class.getName() + "<"
+              + String.class.getName() + "," + String.class.getName() + ">," + List.class.getName()
+              + "<" + List.class.getName() + "<" + Intf.class.getName() + ">>>", sb.toString());
+        } else {
+          throw new RuntimeException(propertyName);
+        }
+      }
+    });
+  }
+
+  /**
+   * Make sure primitive properties can be returned.
+   */
+  public void testPrimitiveProperty() {
+    AutoBean<Intf> auto = factory.intf();
+    Intf intf = auto.as();
+
+    assertNull(intf.getString());
+    intf.setString("Hello world!");
+    assertEquals("Hello world!", intf.getString());
+
+    assertEquals(0, intf.getInt());
+    intf.setInt(42);
+    assertEquals(42, intf.getInt());
+  }
+
+  public void testTags() {
+    AutoBean<Intf> auto = factory.intf();
+    auto.setTag("test", 42);
+    assertEquals(42, auto.getTag("test"));
+  }
+
+  public void testTraversal() {
+    final AutoBean<OtherIntf> other = factory.otherIntf();
+    final AutoBean<Intf> intf = factory.intf();
+    final AutoBean<HasBoolean> hasBoolean = factory.hasBoolean();
+    other.as().setIntf(intf.as());
+    other.as().setHasBoolean(hasBoolean.as());
+    intf.as().setInt(42);
+    hasBoolean.as().setGet(true);
+    hasBoolean.as().setHas(true);
+    hasBoolean.as().setIs(true);
+
+    class Checker extends AutoBeanVisitor {
+      boolean seenHasBoolean;
+      boolean seenIntf;
+      boolean seenOther;
+
+      @Override
+      public void endVisitReferenceProperty(String propertyName, AutoBean<?> value,
+          PropertyContext ctx) {
+        if ("hasBoolean".equals(propertyName)) {
+          assertSame(hasBoolean, value);
+          assertEquals(HasBoolean.class, ctx.getType());
+        } else if ("intf".equals(propertyName)) {
+          assertSame(intf, value);
+          assertEquals(Intf.class, ctx.getType());
+        } else if ("unreferenced".equals(propertyName)) {
+          assertNull(value);
+          assertEquals(UnreferencedInFactory.class, ctx.getType());
+        } else {
+          fail("Unexpecetd property " + propertyName);
+        }
+      }
+
+      @Override
+      public void endVisitValueProperty(String propertyName, Object value, PropertyContext ctx) {
+        if ("int".equals(propertyName)) {
+          assertEquals(42, value);
+          assertEquals(int.class, ctx.getType());
+        } else if ("string".equals(propertyName)) {
+          assertNull(value);
+          assertEquals(String.class, ctx.getType());
+        } else if ("get".equals(propertyName) || "has".equals(propertyName)
+            || "is".equals(propertyName)) {
+          assertEquals(boolean.class, ctx.getType());
+          assertTrue((Boolean) value);
+        } else {
+          fail("Unknown value property " + propertyName);
+        }
+      }
+
+      @Override
+      public boolean visit(AutoBean<?> bean, Context ctx) {
+        if (bean == hasBoolean) {
+          seenHasBoolean = true;
+        } else if (bean == intf) {
+          seenIntf = true;
+        } else if (bean == other) {
+          seenOther = true;
+        } else {
+          fail("Unknown AutoBean");
+        }
+        return true;
+      }
+
+      void check() {
+        assertTrue(seenHasBoolean);
+        assertTrue(seenIntf);
+        assertTrue(seenOther);
+      }
+    }
+    Checker c = new Checker();
+    other.accept(c);
+    c.check();
+  }
+
+  public void testType() {
+    assertEquals(Intf.class, factory.intf().getType());
+  }
+
+  /**
+   * Ensure that a totally automatic bean can't be unwrapped, since the
+   * generated mapper depends on the AutoBean.
+   */
+  public void testUnwrappingSimpleBean() {
+    AutoBean<Intf> auto = factory.intf();
+    try {
+      auto.unwrap();
+      fail();
+    } catch (IllegalStateException expected) {
+    }
+  }
+
+  public void testWrapped() {
+    RealIntf real = new RealIntf();
+    AutoBean<Intf> auto = factory.intf(real);
+    Intf intf = auto.as();
+
+    assertNotSame(real, intf);
+    assertNull(intf.getString());
+    assertEquals(0, intf.getInt());
+
+    real.string = "blah";
+    assertEquals("blah", intf.getString());
+    real.i = 42;
+    assertEquals(42, intf.getInt());
+
+    intf.setString("bar");
+    assertEquals("bar", real.string);
+
+    intf.setInt(41);
+    assertEquals(41, real.i);
+
+    AutoBean<Intf> rewrapped = factory.intf(real);
+    assertSame(auto, rewrapped);
+
+    // Disconnect the wrapper, make sure it shuts down correctly.
+    Intf unwrapped = auto.unwrap();
+    assertSame(real, unwrapped);
+    assertNull(AutoBeanUtils.getAutoBean(real));
+    try {
+      intf.setInt(42);
+      fail("Should have thrown exception");
+    } catch (IllegalStateException expected) {
+    }
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    factory = GWT.create(Factory.class);
+  }
+}
diff --git a/user/test/com/google/web/bindery/autobean/shared/AutoBeanCodexTest.java b/user/test/com/google/web/bindery/autobean/shared/AutoBeanCodexTest.java
new file mode 100644
index 0000000..13f69b3
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/shared/AutoBeanCodexTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.web.bindery.autobean.shared;
+
+import com.google.web.bindery.autobean.shared.AutoBean.PropertyName;
+import com.google.web.bindery.autobean.shared.impl.EnumMap;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simple encoding / decoding tests for the AutoBeanCodex.
+ */
+public class AutoBeanCodexTest extends GWTTestCase {
+  /**
+   * Protected so that the JRE-only test can instantiate instances.
+   */
+  protected interface Factory extends AutoBeanFactory {
+    AutoBean<HasSplittable> hasAutoBean();
+
+    AutoBean<HasCycle> hasCycle();
+
+    AutoBean<HasEnum> hasEnum();
+
+    AutoBean<HasList> hasList();
+
+    AutoBean<HasMap> hasMap();
+
+    AutoBean<HasSimple> hasSimple();
+
+    AutoBean<Simple> simple();
+  }
+
+  /*
+   * These enums are used to verify that a List<Enum> or Map<Enum, Enum> pulls
+   * in the necessary metadata.
+   */
+  enum EnumReachableThroughList {
+    FOO_LIST
+  }
+
+  enum EnumReachableThroughMapKey {
+    FOO_KEY
+  }
+
+  enum EnumReachableThroughMapValue {
+    FOO_VALUE
+  }
+
+  /**
+   * Used to test that cycles are detected.
+   */
+  interface HasCycle {
+    List<HasCycle> getCycle();
+
+    void setCycle(List<HasCycle> cycle);
+  }
+
+  interface HasEnum {
+    MyEnum getEnum();
+
+    List<MyEnum> getEnums();
+
+    Map<MyEnum, Integer> getMap();
+
+    List<EnumReachableThroughList> getParameterizedList();
+
+    Map<EnumReachableThroughMapKey, EnumReachableThroughMapValue> getParameterizedMap();
+
+    void setEnum(MyEnum value);
+
+    void setEnums(List<MyEnum> value);
+
+    void setMap(Map<MyEnum, Integer> value);
+  }
+
+  interface HasList {
+    List<Integer> getIntList();
+
+    List<Simple> getList();
+
+    void setIntList(List<Integer> list);
+
+    void setList(List<Simple> list);
+  }
+
+  interface HasMap {
+    Map<Simple, Simple> getComplexMap();
+
+    Map<Map<String, String>, Map<String, String>> getNestedMap();
+
+    Map<String, Simple> getSimpleMap();
+
+    void setComplexMap(Map<Simple, Simple> map);
+
+    void setNestedMap(Map<Map<String, String>, Map<String, String>> map);
+
+    void setSimpleMap(Map<String, Simple> map);
+  }
+
+  interface HasSimple {
+    Simple getSimple();
+
+    void setSimple(Simple s);
+  }
+
+  interface HasSplittable {
+    Splittable getSimple();
+
+    List<Splittable> getSimpleList();
+
+    Map<Splittable, Splittable> getSplittableMap();
+
+    Splittable getString();
+
+    void setSimple(Splittable simple);
+
+    void setSimpleList(List<Splittable> simple);
+
+    void setSplittableMap(Map<Splittable, Splittable> map);
+
+    void setString(Splittable s);
+  }
+
+  enum MyEnum {
+    FOO, BAR,
+    // The eclipse formatter wants to put this annotation inline
+    @PropertyName("quux")
+    BAZ;
+  }
+
+  interface ReachableOnlyFromParameterization extends Simple {
+  }
+
+  interface Simple {
+    int getInt();
+
+    String getString();
+
+    Boolean hasOtherBoolean();
+
+    boolean isBoolean();
+
+    void setBoolean(boolean b);
+
+    void setInt(int i);
+
+    void setOtherBoolean(Boolean b);
+
+    void setString(String s);
+  }
+
+  protected Factory f;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.web.bindery.autobean.AutoBean";
+  }
+
+  public void testCycle() {
+    AutoBean<HasCycle> bean = f.hasCycle();
+    bean.as().setCycle(Arrays.asList(bean.as()));
+    try {
+      checkEncode(bean);
+      fail("Should not have encoded");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  public void testEmptyList() {
+    AutoBean<HasList> bean = f.hasList();
+    bean.as().setList(Collections.<Simple> emptyList());
+    AutoBean<HasList> decodedBean = checkEncode(bean);
+    assertNotNull(decodedBean.as().getList());
+    assertTrue(decodedBean.as().getList().isEmpty());
+  }
+
+  public void testEnum() {
+    EnumMap map = (EnumMap) f;
+    assertEquals("BAR", map.getToken(MyEnum.BAR));
+    assertEquals("quux", map.getToken(MyEnum.BAZ));
+    assertEquals(MyEnum.BAR, map.getEnum(MyEnum.class, "BAR"));
+    assertEquals(MyEnum.BAZ, map.getEnum(MyEnum.class, "quux"));
+
+    List<MyEnum> arrayValue = Arrays.asList(MyEnum.FOO, MyEnum.BAR, null, MyEnum.BAZ);
+    Map<MyEnum, Integer> mapValue = new HashMap<MyEnum, Integer>();
+    mapValue.put(MyEnum.FOO, 0);
+    mapValue.put(MyEnum.BAR, 1);
+    mapValue.put(MyEnum.BAZ, 2);
+
+    AutoBean<HasEnum> bean = f.hasEnum();
+    bean.as().setEnum(MyEnum.BAZ);
+    bean.as().setEnums(arrayValue);
+    bean.as().setMap(mapValue);
+
+    Splittable split = AutoBeanCodex.encode(bean);
+    // Make sure the overridden form is always used
+    assertFalse(split.getPayload().contains("BAZ"));
+
+    AutoBean<HasEnum> decoded = checkEncode(bean);
+    assertEquals(MyEnum.BAZ, decoded.as().getEnum());
+    assertEquals(arrayValue, decoded.as().getEnums());
+    assertEquals(mapValue, decoded.as().getMap());
+
+    assertEquals(MyEnum.BAZ, AutoBeanUtils.getAllProperties(bean).get("enum"));
+    bean.as().setEnum(null);
+    assertNull(bean.as().getEnum());
+    assertNull(AutoBeanUtils.getAllProperties(bean).get("enum"));
+    decoded = checkEncode(bean);
+    assertNull(decoded.as().getEnum());
+  }
+
+  /**
+   * Ensures that enum types that are reachable only through a method
+   * parameterization are included in the enum map.
+   */
+  public void testEnumReachableOnlyThroughParameterization() {
+    EnumMap map = (EnumMap) f;
+    assertEquals("FOO_LIST", map.getToken(EnumReachableThroughList.FOO_LIST));
+    assertEquals("FOO_KEY", map.getToken(EnumReachableThroughMapKey.FOO_KEY));
+    assertEquals("FOO_VALUE", map.getToken(EnumReachableThroughMapValue.FOO_VALUE));
+    assertEquals(EnumReachableThroughList.FOO_LIST, map.getEnum(EnumReachableThroughList.class,
+        "FOO_LIST"));
+    assertEquals(EnumReachableThroughMapKey.FOO_KEY, map.getEnum(EnumReachableThroughMapKey.class,
+        "FOO_KEY"));
+    assertEquals(EnumReachableThroughMapValue.FOO_VALUE, map.getEnum(
+        EnumReachableThroughMapValue.class, "FOO_VALUE"));
+  }
+
+  public void testMap() {
+    AutoBean<HasMap> bean = f.hasMap();
+    Map<String, Simple> map = new HashMap<String, Simple>();
+    Map<Simple, Simple> complex = new HashMap<Simple, Simple>();
+    bean.as().setSimpleMap(map);
+    bean.as().setComplexMap(complex);
+
+    for (int i = 0, j = 5; i < j; i++) {
+      Simple s = f.simple().as();
+      s.setInt(i);
+      map.put(String.valueOf(i), s);
+
+      Simple key = f.simple().as();
+      key.setString(String.valueOf(i));
+      complex.put(key, s);
+    }
+
+    AutoBean<HasMap> decoded = checkEncode(bean);
+    map = decoded.as().getSimpleMap();
+    complex = decoded.as().getComplexMap();
+    assertEquals(5, map.size());
+    for (int i = 0, j = 5; i < j; i++) {
+      Simple s = map.get(String.valueOf(i));
+      assertNotNull(s);
+      assertEquals(i, s.getInt());
+    }
+    assertEquals(5, complex.size());
+    for (Map.Entry<Simple, Simple> entry : complex.entrySet()) {
+      assertEquals(entry.getKey().getString(), String.valueOf(entry.getValue().getInt()));
+    }
+  }
+
+  /**
+   * Verify that arbitrarily complicated Maps of Maps work.
+   */
+  public void testNestedMap() {
+    Map<String, String> key = new HashMap<String, String>();
+    key.put("a", "b");
+
+    Map<String, String> value = new HashMap<String, String>();
+    value.put("c", "d");
+
+    Map<Map<String, String>, Map<String, String>> test =
+        new HashMap<Map<String, String>, Map<String, String>>();
+    test.put(key, value);
+
+    AutoBean<HasMap> bean = f.hasMap();
+    bean.as().setNestedMap(test);
+
+    AutoBean<HasMap> decoded = checkEncode(bean);
+    assertEquals(1, decoded.as().getNestedMap().size());
+  }
+
+  public void testNull() {
+    AutoBean<Simple> bean = f.simple();
+    AutoBean<Simple> decodedBean = checkEncode(bean);
+    assertNull(decodedBean.as().getString());
+  }
+
+  public void testSimple() {
+    AutoBean<Simple> bean = f.simple();
+    Simple simple = bean.as();
+    simple.setBoolean(true);
+    simple.setInt(42);
+    simple.setOtherBoolean(true);
+    simple.setString("Hello World!");
+
+    AutoBean<Simple> decodedBean = checkEncode(bean);
+    assertTrue(AutoBeanUtils.diff(bean, decodedBean).isEmpty());
+    assertTrue(decodedBean.as().isBoolean());
+    assertTrue(decodedBean.as().hasOtherBoolean());
+
+    AutoBean<HasSimple> bean2 = f.hasSimple();
+    bean2.as().setSimple(simple);
+
+    AutoBean<HasSimple> decodedBean2 = checkEncode(bean2);
+    assertNotNull(decodedBean2.as().getSimple());
+    assertTrue(AutoBeanUtils.diff(bean, AutoBeanUtils.getAutoBean(decodedBean2.as().getSimple()))
+        .isEmpty());
+
+    AutoBean<HasList> bean3 = f.hasList();
+    bean3.as().setIntList(Arrays.asList(1, 2, 3, null, 4, 5));
+    bean3.as().setList(Arrays.asList(simple));
+
+    AutoBean<HasList> decodedBean3 = checkEncode(bean3);
+    assertNotNull(decodedBean3.as().getIntList());
+    assertEquals(Arrays.asList(1, 2, 3, null, 4, 5), decodedBean3.as().getIntList());
+    assertNotNull(decodedBean3.as().getList());
+    assertEquals(1, decodedBean3.as().getList().size());
+    assertTrue(AutoBeanUtils.diff(bean,
+        AutoBeanUtils.getAutoBean(decodedBean3.as().getList().get(0))).isEmpty());
+  }
+
+  public void testSplittable() {
+    AutoBean<Simple> simple = f.simple();
+    simple.as().setString("Simple");
+    AutoBean<HasSplittable> bean = f.hasAutoBean();
+    bean.as().setSimple(AutoBeanCodex.encode(simple));
+    bean.as().setString(ValueCodex.encode("Hello ['\"] world"));
+    List<Splittable> testList =
+        Arrays.asList(AutoBeanCodex.encode(simple), null, AutoBeanCodex.encode(simple));
+    bean.as().setSimpleList(testList);
+    Map<Splittable, Splittable> testMap =
+        Collections.singletonMap(ValueCodex.encode("12345"), ValueCodex.encode("5678"));
+    bean.as().setSplittableMap(testMap);
+
+    AutoBean<HasSplittable> decoded = checkEncode(bean);
+    Splittable toDecode = decoded.as().getSimple();
+    AutoBean<Simple> decodedSimple = AutoBeanCodex.decode(f, Simple.class, toDecode);
+    assertEquals("Simple", decodedSimple.as().getString());
+    assertEquals("Hello ['\"] world", ValueCodex.decode(String.class, decoded.as().getString()));
+    assertEquals("12345", decoded.as().getSplittableMap().keySet().iterator().next().asString());
+    assertEquals("5678", decoded.as().getSplittableMap().values().iterator().next().asString());
+
+    List<Splittable> list = decoded.as().getSimpleList();
+    assertEquals(3, list.size());
+    assertNull(list.get(1));
+    assertEquals("Simple", AutoBeanCodex.decode(f, Simple.class, list.get(2)).as().getString());
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    f = GWT.create(Factory.class);
+  }
+
+  private <T> AutoBean<T> checkEncode(AutoBean<T> bean) {
+    Splittable split = AutoBeanCodex.encode(bean);
+    AutoBean<T> decoded = AutoBeanCodex.decode(f, bean.getType(), split);
+    assertTrue(AutoBeanUtils.deepEquals(bean, decoded));
+    return decoded;
+  }
+}
diff --git a/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java b/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java
new file mode 100644
index 0000000..46a6baf
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2011 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.web.bindery.autobean.shared;
+
+import com.google.web.bindery.autobean.gwt.client.impl.JsoSplittable;
+import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl;
+import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.Coder;
+import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.EncodeState;
+import com.google.web.bindery.autobean.shared.impl.SplittableList;
+import com.google.web.bindery.autobean.shared.impl.SplittableSimpleMap;
+import com.google.web.bindery.autobean.shared.impl.StringQuoter;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests for the underlying Splittable implementation. This test class is not
+ * indicative of code that users would write, it's simply doing spot-checks of
+ * functionality that AbstractAutoBean depends on.
+ */
+public class SplittableTest extends GWTTestCase {
+
+  /**
+   * 
+   */
+  private static final EncodeState testState = EncodeState.forTesting();
+
+  @Override
+  public String getModuleName() {
+    return "com.google.web.bindery.autobean.AutoBean";
+  }
+
+  public void testBasicProperties() {
+    Splittable data = StringQuoter.split("{\"a\":true, \"b\":3, \"c\":\"string\", \"d\":null}");
+    assertTrue("isBoolean", data.get("a").isBoolean());
+    assertTrue("asBoolean", data.get("a").asBoolean());
+    assertTrue("isNumber", data.get("b").isNumber());
+    assertEquals(3.0, data.get("b").asNumber());
+    assertTrue("isString", data.get("c").isString());
+    assertEquals("string", data.get("c").asString());
+    assertTrue("isNull", data.isNull("d"));
+    assertNull("should be null", data.get("d"));
+  }
+
+  /**
+   * Ensure that hashcodes don't leak into the payload.
+   */
+  public void testHashCode() {
+    Splittable data = StringQuoter.split("{\"a\":\"b\"}");
+    int hash = data.hashCode();
+    String payload = data.getPayload();
+    assertFalse(payload, payload.contains("$H"));
+    assertFalse(payload, payload.contains(String.valueOf(hash)));
+    assertEquals(hash, data.hashCode());
+  }
+
+  /**
+   * Splittables are implemented by a couple of different concrete types. We'll
+   * use this method to make sure that the correct implementation type is being
+   * used in various circumstances.
+   */
+  public void testImplementationChoice() {
+    Splittable s = StringQuoter.split("[1,false,\"true\"]");
+    if (GWT.isScript()) {
+      assertTrue("s should be JsoSplittable", s instanceof JsoSplittable);
+      assertTrue("s[0] should be JsoSplittable", s.get(0) instanceof JsoSplittable);
+      assertTrue("s[1] should be JsoSplittable", s.get(1) instanceof JsoSplittable);
+      assertTrue("s[2] should be JsoSplittable", s.get(2) instanceof JsoSplittable);
+    } else {
+      // Using the same types in both pure-JRE and DevMode to avoid JSNI
+      // overhead
+      assertTrue("s should be JsonSplittable", s.getClass().getName().endsWith("JsonSplittable"));
+      assertTrue("s[0] should be JsonSplittable", s.get(0).getClass().getName().endsWith(
+          "JsonSplittable"));
+      assertTrue("s[1] should be JsonSplittable", s.get(1).getClass().getName().endsWith(
+          "JsonSplittable"));
+      assertTrue("s[2] should be JsonSplittable", s.get(2).getClass().getName().endsWith(
+          "JsonSplittable"));
+    }
+  }
+
+  public void testIndexed() {
+    Splittable s = StringQuoter.createIndexed();
+    assertTrue(s.isIndexed());
+    assertFalse(s.isKeyed());
+    assertFalse(s.isString());
+    assertEquals(0, s.size());
+
+    string("foo").assign(s, 0);
+    string("bar").assign(s, 1);
+    string("baz").assign(s, 2);
+
+    assertEquals(3, s.size());
+    assertEquals("[\"foo\",\"bar\",\"baz\"]", s.getPayload());
+
+    string("quux").assign(s, 1);
+    assertEquals("[\"foo\",\"quux\",\"baz\"]", s.getPayload());
+
+    Splittable s2 = s.deepCopy();
+    assertNotSame(s, s2);
+    assertEquals(s.size(), s2.size());
+    for (int i = 0, j = s.size(); i < j; i++) {
+      assertEquals(s.get(i).asString(), s2.get(i).asString());
+    }
+
+    s.setSize(2);
+    assertEquals(2, s.size());
+    assertEquals("[\"foo\",\"quux\"]", s.getPayload());
+
+    // Make sure reified values aren't in the payload
+    Object o = new Object();
+    s.setReified("reified", o);
+    assertFalse(s.getPayload().contains("reified"));
+    assertFalse(s.getPayload().contains("__s"));
+    assertSame(o, s.getReified("reified"));
+  }
+
+  public void testKeyed() {
+    Splittable s = StringQuoter.createSplittable();
+    assertFalse(s.isIndexed());
+    assertTrue(s.isKeyed());
+    assertFalse(s.isString());
+    assertTrue(s.getPropertyKeys().isEmpty());
+
+    string("bar").assign(s, "foo");
+    string("quux").assign(s, "baz");
+
+    // Actual iteration order is undefined
+    assertEquals(new HashSet<String>(Arrays.asList("foo", "baz")), new HashSet<String>(s
+        .getPropertyKeys()));
+
+    assertFalse(s.isNull("foo"));
+    assertTrue(s.isNull("bar"));
+
+    assertEquals("bar", s.get("foo").asString());
+    assertEquals("quux", s.get("baz").asString());
+
+    String payload = s.getPayload();
+    assertTrue(payload.startsWith("{"));
+    assertTrue(payload.endsWith("}"));
+    assertTrue(payload.contains("\"foo\":\"bar\""));
+    assertTrue(payload.contains("\"baz\":\"quux\""));
+
+    Splittable s2 = s.deepCopy();
+    assertNotSame(s, s2);
+    assertEquals("bar", s2.get("foo").asString());
+    assertEquals("quux", s2.get("baz").asString());
+
+    // Make sure reified values aren't in the payload
+    Object o = new Object();
+    s.setReified("reified", o);
+    assertFalse("Should not see reified in " + s.getPayload(), s.getPayload().contains("reified"));
+    assertFalse("Should not see __s in " + s.getPayload(), s.getPayload().contains("__s"));
+    assertSame(o, s.getReified("reified"));
+  }
+
+  public void testNested() {
+    Splittable s = StringQuoter.split("{\"a\":{\"foo\":\"bar\"}}");
+    Splittable a = s.get("a");
+    assertNotNull(a);
+    assertEquals("bar", a.get("foo").asString());
+    assertSame(a, s.get("a"));
+    assertEquals(a, s.get("a"));
+  }
+
+  /**
+   * Tests attributes of the {@link Splittable#NULL} field.
+   */
+  public void testNull() {
+    Splittable n = Splittable.NULL;
+    if (GWT.isScript()) {
+      assertNull(n);
+    } else {
+      assertNotNull(n);
+    }
+    assertFalse("boolean", n.isBoolean());
+    assertFalse("indexed", n.isIndexed());
+    assertFalse("keyed", n.isKeyed());
+    assertFalse("string", n.isString());
+    assertEquals("null", n.getPayload());
+  }
+
+  /**
+   * Extra tests in here due to potential to confuse {@code false} and
+   * {@code null} values.
+   */
+  public void testSplittableListBoolean() {
+    Coder boolCoder = AutoBeanCodexImpl.valueCoder(Boolean.class);
+    Splittable s = StringQuoter.createIndexed();
+    bool(false).assign(s, 0);
+    assertFalse("0 should not be null", s.isNull(0));
+    assertTrue("s[0] should be a boolean", s.get(0).isBoolean());
+    assertFalse("s[0] should be false", s.get(0).asBoolean());
+    assertNotNull("Null decode", ValueCodex.decode(Boolean.class, s.get(0)));
+    Object decodedBoolean = boolCoder.decode(testState, s.get(0));
+    assertNotNull("decode should not return null", decodedBoolean);
+    assertFalse("decoded value should be false", (Boolean) decodedBoolean);
+
+    bool(true).assign(s, 1);
+    assertTrue("s[1] should be a boolean", s.get(1).isBoolean());
+    assertTrue("s[1] should be true", s.get(1).asBoolean());
+    assertTrue("boolCoder 1", (Boolean) boolCoder.decode(testState, s.get(1)));
+
+    Splittable.NULL.assign(s, 2);
+    assertTrue("3 should be null", s.isNull(3));
+    assertEquals("payload", "[false,true,null]", s.getPayload());
+    List<Boolean> boolList = new SplittableList<Boolean>(s, boolCoder, testState);
+    assertEquals("boolList", Arrays.<Boolean> asList(false, true, null), boolList);
+  }
+
+  /**
+   * Extra tests in here due to potential to confuse 0 and {@code null} values.
+   */
+  public void testSplittableListNumbers() {
+    Coder intCoder = AutoBeanCodexImpl.valueCoder(Integer.class);
+    Coder doubleCoder = AutoBeanCodexImpl.valueCoder(Double.class);
+    Splittable s = StringQuoter.createIndexed();
+    number(0).assign(s, 0);
+    assertFalse("0 should not be null", s.isNull(0));
+    assertTrue("s[0] should be a number", s.get(0).isNumber());
+    assertNotNull("Null decode", ValueCodex.decode(Integer.class, s.get(0)));
+    Object decodedInt = intCoder.decode(testState, s.get(0));
+    assertNotNull("decode should not return null", decodedInt);
+    assertEquals("intCoder 0", Integer.valueOf(0), decodedInt);
+    assertEquals("doubleCoder 0", Double.valueOf(0), doubleCoder.decode(testState, s.get(0)));
+
+    number(3.141592).assign(s, 1);
+    assertEquals("intCoder 1", Integer.valueOf(3), intCoder.decode(testState, s.get(1)));
+    assertEquals("doubleCoder 1", Double.valueOf(3.141592), doubleCoder.decode(testState, s.get(1)));
+
+    number(42).assign(s, 2);
+    Splittable.NULL.assign(s, 3);
+    assertTrue("3 should be null", s.isNull(3));
+    assertEquals("payload", "[0,3.141592,42,null]", s.getPayload());
+    List<Double> doubleList = new SplittableList<Double>(s, doubleCoder, testState);
+    assertEquals(Double.valueOf(0), doubleList.get(0));
+    assertEquals("doubleList", Arrays.<Double> asList(0d, 3.141592, 42d, null), doubleList);
+
+    // Don't share backing data between lists
+    s = StringQuoter.split("[0,3.141592,42,null]");
+    List<Integer> intList = new SplittableList<Integer>(s, intCoder, testState);
+    assertEquals("intList", Arrays.<Integer> asList(0, 3, 42, null), intList);
+  }
+
+  public void testSplittableListString() {
+    Splittable data = StringQuoter.split("[\"Hello\",\"World\"]");
+    SplittableList<String> list =
+        new SplittableList<String>(data, AutoBeanCodexImpl.valueCoder(String.class), testState);
+    assertEquals(2, list.size());
+    assertEquals(Arrays.asList("Hello", "World"), list);
+    list.set(0, "Goodbye");
+    assertEquals(Arrays.asList("Goodbye", "World"), list);
+    assertEquals("[\"Goodbye\",\"World\"]", data.getPayload());
+    list.remove(0);
+    assertEquals(Arrays.asList("World"), list);
+    assertEquals("[\"World\"]", data.getPayload());
+    list.add("Wide");
+    list.add("Web");
+    assertEquals(Arrays.asList("World", "Wide", "Web"), list);
+    assertEquals("[\"World\",\"Wide\",\"Web\"]", data.getPayload());
+  }
+
+  public void testSplittableMapStringString() {
+    Splittable data = StringQuoter.split("{\"foo\":\"bar\",\"baz\":\"quux\",\"isNull\":null}");
+    assertTrue("isNull should be null", data.isNull("isNull"));
+    assertFalse("isNull should not be undefined", data.isUndefined("isNull"));
+    Map<String, String> map =
+        new SplittableSimpleMap<String, String>(data, AutoBeanCodexImpl.valueCoder(String.class),
+            AutoBeanCodexImpl.valueCoder(String.class), testState);
+    assertEquals(3, map.size());
+    assertEquals("bar", map.get("foo"));
+    assertEquals("quux", map.get("baz"));
+    assertTrue("Map should have isNull key", map.containsKey("isNull"));
+    assertNull(map.get("isNull"));
+    assertFalse("Map should not have unknown key", map.containsKey("unknown"));
+
+    map.put("bar", "foo2");
+    assertEquals("foo2", map.get("bar"));
+    String payload = data.getPayload();
+    assertTrue(payload.contains("\"bar\":\"foo2\""));
+    assertTrue(payload.contains("\"isNull\":null"));
+  }
+
+  public void testString() {
+    Splittable s = string("Hello '\" World!");
+    assertFalse(s.isIndexed());
+    assertFalse(s.isKeyed());
+    assertTrue(s.isString());
+    assertEquals("Hello '\" World!", s.asString());
+    assertEquals("\"Hello '\\\" World!\"", s.getPayload());
+  }
+
+  public void testStringEmpty() {
+    Splittable s = string("");
+    assertFalse(s.isIndexed());
+    assertFalse(s.isKeyed());
+    assertTrue(s.isString());
+    assertEquals("", s.asString());
+    assertEquals("\"\"", s.getPayload());
+  }
+
+  private Splittable bool(boolean value) {
+    return StringQuoter.split(String.valueOf(value));
+  }
+
+  private Splittable number(double number) {
+    return StringQuoter.split(String.valueOf(number));
+  }
+
+  private Splittable string(String value) {
+    return StringQuoter.split(StringQuoter.quote(value));
+  }
+}
diff --git a/user/test/com/google/web/bindery/autobean/vm/AutoBeanCodexJreTest.java b/user/test/com/google/web/bindery/autobean/vm/AutoBeanCodexJreTest.java
new file mode 100644
index 0000000..46adb69
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/vm/AutoBeanCodexJreTest.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.web.bindery.autobean.vm;
+
+import com.google.web.bindery.autobean.shared.AutoBeanCodexTest;
+
+/**
+ * Runs AutoBeanCodexTest in pure-JRE mode.
+ */
+public class AutoBeanCodexJreTest extends AutoBeanCodexTest {
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    f = AutoBeanFactorySource.create(Factory.class);
+  }
+
+}
diff --git a/user/test/com/google/web/bindery/autobean/vm/AutoBeanJreTest.java b/user/test/com/google/web/bindery/autobean/vm/AutoBeanJreTest.java
new file mode 100644
index 0000000..e56be29
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/vm/AutoBeanJreTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.web.bindery.autobean.vm;
+
+import com.google.web.bindery.autobean.gwt.client.AutoBeanTest;
+
+/**
+ * Runs the AutoBeanTests against the JRE implementation.
+ */
+public class AutoBeanJreTest extends AutoBeanTest {
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    factory = AutoBeanFactorySource.create(Factory.class);
+  }
+}
diff --git a/user/test/com/google/web/bindery/autobean/vm/SplittableJreTest.java b/user/test/com/google/web/bindery/autobean/vm/SplittableJreTest.java
new file mode 100644
index 0000000..ddb9126
--- /dev/null
+++ b/user/test/com/google/web/bindery/autobean/vm/SplittableJreTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 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.web.bindery.autobean.vm;
+
+import com.google.web.bindery.autobean.shared.SplittableTest;
+
+/**
+ * A JRE-only version of SplittableTest.
+ */
+public class SplittableJreTest extends SplittableTest {
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+}
diff --git a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTestBase.java b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTestBase.java
index 17958d7..02a347b 100644
--- a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTestBase.java
+++ b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTestBase.java
@@ -15,8 +15,8 @@
  */
 package com.google.web.bindery.requestfactory.gwt.client;
 
-import com.google.gwt.autobean.shared.AutoBean;
-import com.google.gwt.autobean.shared.AutoBeanUtils;
+import com.google.web.bindery.autobean.shared.AutoBean;
+import com.google.web.bindery.autobean.shared.AutoBeanUtils;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.SimpleEventBus;
diff --git a/user/test/com/google/web/bindery/requestfactory/gwt/rebind/model/RequestFactoryModelTest.java b/user/test/com/google/web/bindery/requestfactory/gwt/rebind/model/RequestFactoryModelTest.java
index c548a6c..14af62b 100644
--- a/user/test/com/google/web/bindery/requestfactory/gwt/rebind/model/RequestFactoryModelTest.java
+++ b/user/test/com/google/web/bindery/requestfactory/gwt/rebind/model/RequestFactoryModelTest.java
@@ -15,7 +15,7 @@
  */
 package com.google.web.bindery.requestfactory.gwt.rebind.model;
 
-import com.google.gwt.autobean.shared.Splittable;
+import com.google.web.bindery.autobean.shared.Splittable;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.javac.CompilationState;