Adding Gwt 2.1.0 RC1 changes from trunk.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.1@8955 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/build.xml b/dev/build.xml
index 2a16924..00a5c2b 100755
--- a/dev/build.xml
+++ b/dev/build.xml
@@ -100,7 +100,7 @@
           <include name="htmlunit/htmlunit-r5940/htmlunit-r5940.jar" />
           <include name="htmlunit/htmlunit-r5940/htmlunit-core-js-r5940.jar" />
           <include name="nekohtml/nekohtml-1.9.13.jar" />
-          <include name="streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-rebased.jar" />
+          <include name="streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-1.5-rebased.jar" />
           <include name="xalan/xalan-2.7.1.jar" />
           <include name="xerces/xerces-2_9_1/serializer.jar" />
           <include name="xerces/xerces-2_9_1/xercesImpl-NoMetaInf.jar" />
@@ -124,7 +124,7 @@
           <zipfileset src="${gwt.tools.lib}/jetty/jetty-6.1.11.jar" />
           <zipfileset src="${gwt.tools.lib}/icu4j/icu4j-4_4_1.jar" />
           <zipfileset src="${gwt.tools.lib}/protobuf/protobuf-2.2.0/protobuf-java-rebased-2.2.0.jar" />
-          <zipfileset src="${gwt.tools.lib}/streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-rebased.jar" />
+          <zipfileset src="${gwt.tools.lib}/streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-1.5-rebased.jar" />
           <zipfileset src="${gwt.tools.lib}/tomcat/ant-launcher-1.6.5.jar" />
           <zipfileset src="${gwt.tools.lib}/tomcat/catalina-1.0.jar" />
           <zipfileset src="${gwt.tools.lib}/tomcat/catalina-optional-1.0.jar" />
diff --git a/doc/build.xml b/doc/build.xml
index 1770d9d..6b40bb8 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -29,6 +29,9 @@
     <pathelement location="${gwt.user.jar}" />
     <pathelement location="${gwt.dev.jar}" />
     <pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
+    <pathelement location="${gwt.tools}/redist/json/r2_20080312/json-1.5.jar" />
+    <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA.jar" />
+    <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA-sources.jar" />
     <pathelement location="${gwt.tools.lib}/jfreechart/jfreechart-1.0.3.jar" />
   </path>
 
diff --git a/eclipse/samples/DynaTableRf/.classpath b/eclipse/samples/DynaTableRf/.classpath
index c0fb748..f2c5ce7 100644
--- a/eclipse/samples/DynaTableRf/.classpath
+++ b/eclipse/samples/DynaTableRf/.classpath
@@ -6,6 +6,6 @@
 	<classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
 	<classpathentry kind="var" path="GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA.jar" sourcepath="/GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar"/>
 	<classpathentry kind="var" path="GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar"/>
-	<classpathentry kind="var" path="GWT_TOOLS/redist/json/r2_20080312/json.jar"/>
+	<classpathentry kind="var" path="GWT_TOOLS/redist/json/r2_20080312/json-1.5.jar"/>
 	<classpathentry kind="output" path="war/WEB-INF/classes"/>
 </classpath>
diff --git a/eclipse/user/.classpath b/eclipse/user/.classpath
index 85deb35..605bfdf 100644
--- a/eclipse/user/.classpath
+++ b/eclipse/user/.classpath
@@ -40,6 +40,6 @@
 	<classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar"/>
 	<classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" sourcepath="/GWT_TOOLS/lib/jetty/jetty-6.1.11-src.zip"/>
 	<classpathentry kind="var" path="GWT_TOOLS/lib/guava/guava-r06/guava-r06-rebased.jar"/>
-	<classpathentry kind="var" path="GWT_TOOLS/lib/streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-rebased.jar"/>
+	<classpathentry kind="var" path="GWT_TOOLS/lib/streamhtmlparser/streamhtmlparser-jsilver-r10/streamhtmlparser-jsilver-r10-1.5-rebased.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
index 932bfe6..4dd6e1d 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
@@ -18,7 +18,6 @@
 
   <inherits name='com.google.gwt.user.User' />
   <inherits name='com.google.gwt.editor.Editor' />
-  <inherits name='com.google.gwt.app.App' />
   <inherits name='com.google.gwt.requestfactory.RequestFactory' />
   
   <inherits name='com.google.gwt.logging.Logging'/>
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.java
index 56d6936..3a210a2 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.java
@@ -17,7 +17,7 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.editor.client.Editor;
-import com.google.gwt.editor.client.ui.ValueBoxEditorDecorator;
+import com.google.gwt.editor.ui.client.ValueBoxEditorDecorator;
 import com.google.gwt.sample.dynatablerf.shared.AddressProxy;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.ui.xml
index 4db5bc7..52c2792 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.ui.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/AddressEditor.ui.xml
@@ -1,5 +1,6 @@
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
-  xmlns:a='urn:import:com.google.gwt.app.client' xmlns:e='urn:import:com.google.gwt.editor.client.ui'>
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
+    xmlns:g='urn:import:com.google.gwt.user.client.ui'
+    xmlns:e='urn:import:com.google.gwt.editor.ui.client'>
   <ui:style src="../common.css">
     
   </ui:style>
@@ -33,7 +34,7 @@
       <e:ValueBoxEditorDecorator ui:field="zip"
         stylePrimaryName="{style.editField}">
         <e:valuebox>
-          <a:IntegerBox stylePrimaryName="{style.editField}" />
+          <g:IntegerBox stylePrimaryName="{style.editField}" />
         </e:valuebox>
       </e:ValueBoxEditorDecorator>
       <br />
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml
index 7fbb781..5d365e6 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml
@@ -1,6 +1,6 @@
 <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
   xmlns:dt='urn:import:com.google.gwt.sample.dynatablerf.client.widgets'
-  xmlns:e='urn:import:com.google.gwt.editor.client.ui'>
+  xmlns:e='urn:import:com.google.gwt.editor.ui.client'>
   <ui:style src="../common.css" />
   <g:FlowPanel>
     <dt:NameLabel ui:field="nameLabel" stylePrimaryName="{style.editField}" />
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
index 658ec32..0ecdd4b 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
@@ -19,7 +19,7 @@
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.editor.client.Editor;
-import com.google.gwt.editor.client.ui.ValueBoxEditorDecorator;
+import com.google.gwt.editor.ui.client.ValueBoxEditorDecorator;
 import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
 import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
 import com.google.gwt.uibinder.client.UiBinder;
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
index 0c450e3..3b29ba3 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
@@ -1,6 +1,6 @@
 <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
   xmlns:dt='urn:import:com.google.gwt.sample.dynatablerf.client.widgets'
-  xmlns:e='urn:import:com.google.gwt.editor.client.ui'>
+  xmlns:e='urn:import:com.google.gwt.editor.ui.client'>
   <ui:style src="../common.css">
     
   </ui:style>
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/ExpensesCommon.gwt.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/ExpensesCommon.gwt.xml
index e64917c..3b81103 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/ExpensesCommon.gwt.xml
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/ExpensesCommon.gwt.xml
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
 <module>
-  <inherits name='com.google.gwt.app.App' />
+  <inherits name='com.google.gwt.activity.Activity' />
+  <inherits name='com.google.gwt.place.Place' />
   <inherits name='com.google.gwt.requestfactory.RequestFactory'/>
   <!--  <inherits name='com.google.gwt.sample.expenses.client.style.Style'/> -->
   <inherits name='com.google.gwt.mobile.Mobile'/>
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
index f29dec2..a7bc579 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
@@ -19,11 +19,11 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.SimpleEventBus;
-import com.google.gwt.requestfactory.client.AuthenticationFailureHandler;
-import com.google.gwt.requestfactory.client.LoginWidget;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.shared.RequestEvent;
 import com.google.gwt.requestfactory.shared.UserInformationProxy;
+import com.google.gwt.requestfactory.ui.client.AuthenticationFailureHandler;
+import com.google.gwt.requestfactory.ui.client.LoginWidget;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobile.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobile.java
index 3c87354..24ec2f4 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobile.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobile.java
@@ -19,11 +19,11 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.SimpleEventBus;
-import com.google.gwt.requestfactory.client.AuthenticationFailureHandler;
-import com.google.gwt.requestfactory.client.LoginWidget;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.shared.RequestEvent;
 import com.google.gwt.requestfactory.shared.UserInformationProxy;
+import com.google.gwt.requestfactory.ui.client.AuthenticationFailureHandler;
+import com.google.gwt.requestfactory.ui.client.LoginWidget;
 import com.google.gwt.sample.expenses.client.request.EmployeeProxy;
 import com.google.gwt.sample.expenses.client.request.ExpensesRequestFactory;
 import com.google.gwt.user.client.Window;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.java
index e2416d4..cd848fc 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.java
@@ -19,7 +19,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.shared.EventBus;
-import com.google.gwt.requestfactory.client.LoginWidget;
+import com.google.gwt.requestfactory.ui.client.LoginWidget;
 import com.google.gwt.sample.expenses.client.request.EmployeeProxy;
 import com.google.gwt.sample.expenses.client.request.ExpenseProxy;
 import com.google.gwt.sample.expenses.client.request.ExpensesRequestFactory;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.ui.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.ui.xml
index cfb495b..6a392fd 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.ui.xml
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesMobileShell.ui.xml
@@ -2,7 +2,7 @@
 <ui:UiBinder
   xmlns:ui='urn:ui:com.google.gwt.uibinder'
   xmlns:m='urn:import:com.google.gwt.mobile.client'
-  xmlns:r='urn:import:com.google.gwt.requestfactory.client'
+  xmlns:r='urn:import:com.google.gwt.requestfactory.ui.client'
   xmlns:g='urn:import:com.google.gwt.user.client.ui'>
 
   <ui:style field='mobile' src='mobile.css'/>
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
index 67e5d19..9d80fa8 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
@@ -21,7 +21,7 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.layout.client.Layout;
 import com.google.gwt.layout.client.Layout.Layer;
-import com.google.gwt.requestfactory.client.LoginWidget;
+import com.google.gwt.requestfactory.ui.client.LoginWidget;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.client.ui.Composite;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
index aea7ece..0ec4a00 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
@@ -3,7 +3,7 @@
   xmlns:ui='urn:ui:com.google.gwt.uibinder'
   xmlns:g='urn:import:com.google.gwt.user.client.ui'
   xmlns:m='urn:import:com.google.gwt.mobile.client'
-  xmlns:r='urn:import:com.google.gwt.requestfactory.client'
+  xmlns:r='urn:import:com.google.gwt.requestfactory.ui.client'
   xmlns:e='urn:import:com.google.gwt.sample.expenses.client'>
 
   <ui:with field='styles' type='com.google.gwt.sample.expenses.client.style.Styles' />
diff --git a/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyEditActivity.java
similarity index 87%
rename from user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyEditActivity.java
index db9793c..a2c8ada 100644
--- a/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyEditActivity.java
@@ -13,10 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
-import com.google.gwt.app.place.ProxyPlace.Operation;
+import com.google.gwt.activity.shared.Activity;
 import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.place.shared.PlaceController;
 import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
@@ -24,18 +25,18 @@
 import com.google.gwt.requestfactory.shared.RequestContext;
 import com.google.gwt.requestfactory.shared.ServerFailure;
 import com.google.gwt.requestfactory.shared.Violation;
+import com.google.gwt.sample.expenses.client.place.ProxyPlace.Operation;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 
 import java.util.Set;
 
 /**
+ * Abstract activity for editing a record. Subclasses must provide access to the
+ * request that will be fired when Save is clicked.
  * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * </p>
- * Abstract activity for editing a record.
+ * Instances are not reusable. Once an activity is stoped, it cannot be
+ * restarted.
  * 
  * @param <P> the type of Proxy being edited
  */
@@ -63,8 +64,7 @@
   }
 
   public String mayStop() {
-    if (isWaiting()
-        || (editorDriver != null && editorDriver.flush().isChanged())) {
+    if (isWaiting() || changed()) {
       return "Are you sure you want to abandon your changes?";
     }
 
@@ -76,10 +76,15 @@
   }
 
   public void onStop() {
+    view.setDelegate(null);
     editorDriver = null;
   }
 
   public void saveClicked() {
+    if (!changed()) {
+      return;
+    }
+    
     setWaiting(true);
     editorDriver.flush().fire(new Receiver<Void>() {
       /*
@@ -158,6 +163,10 @@
     return (EntityProxyId<P>) getProxy().stableId();
   }
 
+  private boolean changed() {
+    return editorDriver != null && editorDriver.flush().isChanged();
+  }
+
   /**
    * @return true if we're waiting for an rpc response.
    */
diff --git a/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListActivity.java
similarity index 93%
rename from user/src/com/google/gwt/app/place/AbstractProxyListActivity.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListActivity.java
index deb1db8..5058fa1 100644
--- a/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListActivity.java
@@ -13,17 +13,21 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
-import com.google.gwt.app.place.ProxyPlace.Operation;
+import com.google.gwt.activity.shared.Activity;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceChangeEvent;
+import com.google.gwt.place.shared.PlaceController;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyChange;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.shared.Request;
 import com.google.gwt.requestfactory.shared.WriteOperation;
+import com.google.gwt.sample.expenses.client.place.ProxyPlace.Operation;
 import com.google.gwt.user.cellview.client.AbstractHasData;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 import com.google.gwt.view.client.HasData;
@@ -39,22 +43,19 @@
 import java.util.Map;
 
 /**
- * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * </p>
- * Abstract activity for requesting and displaying a list of {@link EntityProxy}
- * .
+ * Abstract activity for displaying a list of {@link EntityProxy}. These
+ * activities are not re-usable. Once they are stopped, they cannot be
+ * restarted.
  * <p>
  * Subclasses must:
  * 
  * <ul>
- * <li>implement methods to provide a full count, and request a specific
  * <li>provide a {@link ProxyListView}
+ * <li>implement method to request a full count
+ * <li>implement method to find a range of entities
  * <li>respond to "show details" commands
  * </ul>
- * 
+ * <p>
  * Only the properties required by the view will be requested.
  * 
  * @param <P> the type of {@link EntityProxy} listed
@@ -185,6 +186,7 @@
   }
 
   public void start(AcceptsOneWidget display, EventBus eventBus) {
+    view.setDelegate(this);
     EntityProxyChange.registerForProxyType(eventBus, proxyClass,
         new EntityProxyChange.Handler<P>() {
           public void onProxyChange(EntityProxyChange<P> event) {
diff --git a/user/src/com/google/gwt/app/place/AbstractProxyListView.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListView.java
similarity index 89%
rename from user/src/com/google/gwt/app/place/AbstractProxyListView.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListView.java
index ea51991..c05fdd8 100644
--- a/user/src/com/google/gwt/app/place/AbstractProxyListView.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/AbstractProxyListView.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -24,11 +24,8 @@
 import com.google.gwt.view.client.HasData;
 
 /**
- * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * 
+ * Abstract implementation of ProxyListView.
+ *
  * @param <P> the type of the proxy
  */
 public abstract class AbstractProxyListView<P extends EntityProxy> extends
@@ -61,6 +58,7 @@
     });
   }
 
+  @Override
   protected void initWidget(Widget widget) {
     throw new UnsupportedOperationException(
         "AbstractRecordListView must be initialized via "
diff --git a/user/src/com/google/gwt/app/place/CreateAndEditProxy.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/CreateAndEditProxy.java
similarity index 82%
rename from user/src/com/google/gwt/app/place/CreateAndEditProxy.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/CreateAndEditProxy.java
index e5d91c7..e8fed9b 100644
--- a/user/src/com/google/gwt/app/place/CreateAndEditProxy.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/CreateAndEditProxy.java
@@ -13,32 +13,36 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.place.shared.PlaceController;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.RequestContext;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 
 /**
- * Extends {@link AbstractProxyEditActivity} to first create an instance to edit
+ * Extends {@link AbstractProxyEditActivity} to first create an instance to
+ * edit.
  * 
  * @param <P> the type of proxy to create and edit
  */
 public abstract class CreateAndEditProxy<P extends EntityProxy> extends AbstractProxyEditActivity<P> {
 
-  private AcceptsOneWidget display;
   private final P proxy;
+  private final PlaceController placeController;
+  private Class<P> proxyClass;
 
   public CreateAndEditProxy(Class<P> proxyClass, RequestContext request,
       ProxyEditView<P, ?> view, PlaceController placeController) {
     super(view, placeController);
     this.proxy = request.create(proxyClass);
+    this.placeController = placeController;
+    this.proxyClass = proxyClass;
   }
 
   @Override
   public void start(AcceptsOneWidget display, EventBus eventBus) {
-    this.display = display;
     super.start(display, eventBus);
   }
 
@@ -51,10 +55,10 @@
   @Override
   protected void exit(boolean saved) {
     if (!saved) {
-      display.setWidget(null);
+      placeController.goTo(new ProxyListPlace(proxyClass));
+    } else {
+      super.exit(saved);
     }
-
-    super.exit(saved);
   }
 
   @Override
diff --git a/user/src/com/google/gwt/app/place/FindAndEditProxy.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/FindAndEditProxy.java
similarity index 90%
rename from user/src/com/google/gwt/app/place/FindAndEditProxy.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/FindAndEditProxy.java
index e478456..a86ba0c 100644
--- a/user/src/com/google/gwt/app/place/FindAndEditProxy.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/FindAndEditProxy.java
@@ -13,9 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.place.shared.PlaceController;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
 import com.google.gwt.requestfactory.shared.Receiver;
@@ -23,7 +24,8 @@
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 
 /**
- * Extends {@link AbstractProxyEditActivity} to work from a {@link EntityProxyId}
+ * Extends {@link AbstractProxyEditActivity} to work from a
+ * {@link EntityProxyId}.
  * 
  * @param <P> the type of proxy to find and edit
  */
diff --git a/user/src/com/google/gwt/app/place/ProxyDetailsView.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyDetailsView.java
similarity index 83%
rename from user/src/com/google/gwt/app/place/ProxyDetailsView.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyDetailsView.java
index 94111d1..2b660d4 100644
--- a/user/src/com/google/gwt/app/place/ProxyDetailsView.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyDetailsView.java
@@ -13,17 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.user.client.TakesValue;
 import com.google.gwt.user.client.ui.IsWidget;
 
 /**
- * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * </p>
  * Implemented by views that show the details of an object.
  *
  * @param <P> the type of object to show
diff --git a/user/src/com/google/gwt/app/place/ProxyEditView.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyEditView.java
similarity index 87%
rename from user/src/com/google/gwt/app/place/ProxyEditView.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyEditView.java
index 987efa5..70e9c6d 100644
--- a/user/src/com/google/gwt/app/place/ProxyEditView.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyEditView.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.editor.client.HasEditorErrors;
 import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
@@ -21,11 +21,6 @@
 import com.google.gwt.user.client.ui.IsWidget;
 
 /**
- * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * </p>
  * Implemented by views that edit {@link EntityProxy}s.
  * 
  * @param <P> the type of the proxy
diff --git a/user/src/com/google/gwt/app/place/ProxyListPlace.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlace.java
similarity index 88%
rename from user/src/com/google/gwt/app/place/ProxyListPlace.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlace.java
index 25b4066..8167386 100644
--- a/user/src/com/google/gwt/app/place/ProxyListPlace.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlace.java
@@ -13,14 +13,16 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 
 /**
- * A place in the app that deals with lists of {@link RequestFactory}
- * proxy objects.
+ * A place in the app that deals with lists of {@link EntityProxy}.
  */
 public class ProxyListPlace extends Place {
 
diff --git a/user/src/com/google/gwt/app/place/ProxyListPlacePicker.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlacePicker.java
similarity index 93%
rename from user/src/com/google/gwt/app/place/ProxyListPlacePicker.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlacePicker.java
index 9dc11eb..0f1d3c6 100644
--- a/user/src/com/google/gwt/app/place/ProxyListPlacePicker.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListPlacePicker.java
@@ -13,12 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.place.shared.PlaceChangeEvent;
+import com.google.gwt.place.shared.PlaceController;
 import com.google.gwt.user.client.ui.HasConstrainedValue;
 
 /**
diff --git a/user/src/com/google/gwt/app/place/ProxyListView.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListView.java
similarity index 90%
rename from user/src/com/google/gwt/app/place/ProxyListView.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListView.java
index 2e0387c..6156ff3 100644
--- a/user/src/com/google/gwt/app/place/ProxyListView.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyListView.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.user.client.ui.IsWidget;
@@ -25,8 +25,8 @@
  * development, and is very likely to be deleted. Use it at your own risk.
  * </span>
  * </p>
- * A view of a list of {@link EntityProxy}s, which declares which properties it is
- * able to display.
+ * A view of a list of {@link EntityProxy}s, which declares which properties it
+ * is able to display.
  * <p>
  * It is expected that such views will typically (eventually) be defined largely
  * in ui.xml files which declare the properties of interest, which is why the
@@ -45,9 +45,12 @@
   }
 
   HasData<P> asHasData();
-  
+
+  /**
+   * @return the set of properties this view displays
+   */
   String[] getPaths();
-  
+
   /**
    * Sets the delegate.
    */
diff --git a/user/src/com/google/gwt/app/place/ProxyPlace.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlace.java
similarity index 95%
rename from user/src/com/google/gwt/app/place/ProxyPlace.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlace.java
index a66ae66..fdb0af8 100644
--- a/user/src/com/google/gwt/app/place/ProxyPlace.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlace.java
@@ -13,8 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
 
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
 import com.google.gwt.requestfactory.shared.RequestFactory;
diff --git a/user/src/com/google/gwt/app/place/ProxyPlaceToListPlace.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlaceToListPlace.java
similarity index 78%
rename from user/src/com/google/gwt/app/place/ProxyPlaceToListPlace.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlaceToListPlace.java
index 038c321..7b15f3c 100644
--- a/user/src/com/google/gwt/app/place/ProxyPlaceToListPlace.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ProxyPlaceToListPlace.java
@@ -13,16 +13,19 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.sample.expenses.client.place;
+
+import com.google.gwt.activity.shared.FilteredActivityMapper;
+import com.google.gwt.place.shared.Place;
 
 /**
- * Converts a {@link #ProxyPlace} to a {@link ProxyListPlace}.
+ * Converts a {@link ProxyPlace} to a {@link ProxyListPlace}.
  */
 public class ProxyPlaceToListPlace implements FilteredActivityMapper.Filter {
 
   /**
-   * Required by {@link FilteredActivityMapper.Filter}, calls
-   * {@link #proxyListPlaceFor()}.
+   * Required by {@link com.google.gwt.app.place.FilteredActivityMapper.Filter}, calls
+   * {@link #proxyListPlaceFor}.
    */
   public Place filter(Place place) {
     return proxyListPlaceFor(place);
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportRequest.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportRequest.java
index 08dcc10..160f277 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportRequest.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportRequest.java
@@ -41,8 +41,8 @@
   /**
    * @return a request object
    */
-  Request<Long> countReportsBySearch(Long employeeId,
-      String department, String startsWith);
+  Request<Long> countReportsBySearch(Long employeeId, String department,
+      String startsWith);
 
   /**
    * @return a request object
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
index ca97c30..2610237 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
@@ -198,7 +198,7 @@
       String className = this.getClass().getName();
       className = className.substring(className.lastIndexOf(".") + 1);
       sendSourceRequest(
-          rc, ShowcaseConstants.DST_SOURCE_RAW + "/" + filename + ".html");
+          rc, ShowcaseConstants.DST_SOURCE_RAW + filename + ".html");
     }
   }
 
@@ -264,7 +264,7 @@
       String className = this.getClass().getName();
       className = className.substring(className.lastIndexOf(".") + 1);
       sendSourceRequest(
-          rc, ShowcaseConstants.DST_SOURCE_EXAMPLE + "/" + className + ".html");
+          rc, ShowcaseConstants.DST_SOURCE_EXAMPLE + className + ".html");
     }
   }
 
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
index c864ce9..3c47105 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
@@ -70,8 +70,10 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * The {@link TreeViewModel} used by the main menu.
@@ -249,6 +251,21 @@
   }
 
   /**
+   * Get the set of all {@link ContentWidget}s used in the model.
+   * 
+   * @return the {@link ContentWidget}s
+   */
+  Set<ContentWidget> getAllContentWidgets() {
+    Set<ContentWidget> widgets = new HashSet<ContentWidget>();
+    for (Category category : categories.getList()) {
+      for (ContentWidget example : category.examples.getList()) {
+        widgets.add(example);
+      }
+    }
+    return widgets;
+  }
+
+  /**
    * Initialize the top level categories in the tree.
    */
   private void initializeTree(ShowcaseConstants constants) {
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
index 75a3a0f..63c4fb9 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
@@ -26,17 +26,22 @@
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.i18n.client.LocaleInfo;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.sample.showcase.client.MainMenuTreeViewModel.Category;
 import com.google.gwt.user.cellview.client.CellTree;
 import com.google.gwt.user.cellview.client.TreeNode;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.view.client.SelectionChangeEvent;
 import com.google.gwt.view.client.SingleSelectionModel;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Entry point classes define <code>onModuleLoad()</code>.
@@ -99,6 +104,7 @@
     final SingleSelectionModel<ContentWidget> selectionModel = new SingleSelectionModel<ContentWidget>();
     final MainMenuTreeViewModel treeModel = new MainMenuTreeViewModel(
         constants, selectionModel);
+    Set<ContentWidget> contentWidgets = treeModel.getAllContentWidgets();
     shell = new ShowcaseShell(treeModel);
     RootLayoutPanel.get().add(shell);
 
@@ -176,9 +182,31 @@
       ContentWidget content = (ContentWidget) category.getChildValue(0);
       selectionModel.setSelected(content, true);
     }
+
+    // Generate a site map.
+    createSiteMap(contentWidgets);
   }
 
   /**
+   * Create a hidden site map for crawlability.
+   * 
+   * @param contentWidgets the {@link ContentWidget}s used in Showcase
+   */
+  private void createSiteMap(Set<ContentWidget> contentWidgets) {
+    SafeHtmlBuilder sb = new SafeHtmlBuilder();
+    for (ContentWidget cw : contentWidgets) {
+      String token = getContentWidgetToken(cw);
+      sb.append(SafeHtmlUtils.fromTrustedString("<a href=\"#" + token + "\">"
+          + token + "</a>"));
+    }
+
+    // Add the site map to the page.
+    HTML siteMap = new HTML(sb.toSafeHtml());
+    siteMap.setVisible(false);
+    RootPanel.get().add(siteMap, 0, 0);
+  }
+  
+  /**
    * Set the content to the {@link ContentWidget}.
    *
    * @param content the {@link ContentWidget} to display
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseShell.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseShell.java
index 6561ae8..418c02d 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseShell.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseShell.java
@@ -255,7 +255,15 @@
     tabStyle.setVisible(content.hasStyle());
     tabSource.setVisible(true);
 
-    // Show the list of raw source files if there are any.
+    /*
+     * Show the list of raw source files if there are any. We need to add at
+     * least one option to the list for crawlability. If we do not, HtmlUnit
+     * innerHtml will close the select tag in the open tag (ie, use a forward
+     * slash instead of a separate close tag) which most browsers parse
+     * incorrectly.
+     */
+    tabSourceList.clear();
+    tabSourceList.addItem("Example");
     List<String> rawFilenames = content.getRawSourceFilenames();
     if (rawFilenames.size() > 0) {
       String text = tabSource.getText();
@@ -263,8 +271,6 @@
         tabSource.setText(text + ":");
       }
       tabSourceList.setVisible(true);
-      tabSourceList.clear();
-      tabSourceList.addItem("Example");
       for (String filename : rawFilenames) {
         tabSourceList.addItem(filename);
       }
diff --git a/user/javadoc/com/google/gwt/examples/cell/CellExample.java b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
new file mode 100644
index 0000000..2c8317c
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
@@ -0,0 +1,82 @@
+/*
+ * 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.examples.cell;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Example of creating a custom {@link Cell}.
+ */
+public class CellExample implements EntryPoint {
+
+  /**
+   * A custom {@link Cell} used to render a string that contains the name of a
+   * color.
+   */
+  private static class ColorCell extends AbstractCell<String> {
+
+    @Override
+    public void render(String value, Object key, SafeHtmlBuilder sb) {
+      /*
+       * Always do a null check on the value. Cell widgets can pass null to
+       * cells if the underlying data contains a null, or if the data arrives
+       * out of order.
+       */
+      if (value == null) {
+        return;
+      }
+
+      // If the value comes from the user, we escape it to avoid XSS attacks.
+      SafeHtml safeValue = SafeHtmlUtils.fromString(value);
+
+      // Append some HTML that sets the text color.
+      sb.appendHtmlConstant("<div style=\"color:" + safeValue.asString()
+          + "\">");
+      sb.append(safeValue);
+      sb.appendHtmlConstant("</div>");
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<String> COLORS = Arrays.asList("red", "green",
+      "blue", "violet", "black", "gray");
+
+  public void onModuleLoad() {
+    // Create a cell to render each value.
+    ColorCell cell = new ColorCell();
+
+    // Use the cell in a CellList.
+    CellList<String> cellList = new CellList<String>(cell);
+
+    // Push the data into the widget.
+    cellList.setRowData(0, COLORS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(cellList);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
new file mode 100644
index 0000000..024a01b
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
@@ -0,0 +1,218 @@
+/*
+ * 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.examples.cell;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.TableCellElement;
+import com.google.gwt.dom.client.TableElement;
+import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Example of creating an editable {@link Cell}. This example creates a cell
+ * that displays a Contact with a checkbox that indicates whether the contact is
+ * a favorite or not.
+ */
+public class EditableCellExample implements EntryPoint {
+
+  /**
+   * A simple data type that represents a contact.
+   */
+  private static class Contact {
+    private final String address;
+    private final String name;
+
+    public Contact(String name, String address) {
+      this.name = name;
+      this.address = address;
+    }
+  }
+
+  /**
+   * A custom {@link Cell} used to render a {@link Contact}. We extend
+   * {@link AbstractCell} because it provides reasonable implementations of
+   * methods that work for most use cases.
+   */
+  private class ContactCell extends AbstractCell<Contact> {
+
+    public ContactCell() {
+      // Our cell responds to change events and keydown events.
+      super("change", "keydown");
+    }
+
+    @Override
+    public void onBrowserEvent(Element parent, Contact value, Object key,
+        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+      // Check that the value is not null.
+      if (value == null) {
+        return;
+      }
+
+      // Call the super handler, which handlers the enter key.
+      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+
+      // Handle click events.
+      if ("change".equals(event.getType())) {
+        updateFavorites(parent, value);
+        showCurrentFavorites();
+      }
+    }
+
+    @Override
+    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+      /*
+       * Always do a null check on the value. Cell widgets can pass null to
+       * cells if the underlying data contains a null, or if the data arrives
+       * out of order.
+       */
+      if (value == null) {
+        return;
+      }
+
+      // Add a checkbox. If the contact is a favorite, the box will be checked.
+      sb.appendHtmlConstant("<table><tr><td valign=\"top\">");
+      if (favorites.contains(value)) {
+        sb.appendHtmlConstant("<input type=\"checkbox\" checked=checked/>");
+      } else {
+        sb.appendHtmlConstant("<input type=\"checkbox\" />");
+      }
+      sb.appendHtmlConstant("</td><td>");
+
+      // Display the name in big letters.
+      sb.appendHtmlConstant("<div style=\"size:200%;font-weight:bold;\">");
+      sb.appendEscaped(value.name);
+      sb.appendHtmlConstant("</div>");
+
+      // Display the address in normal text.
+      sb.appendHtmlConstant("<div style=\"padding-left:10px;\">");
+      sb.appendEscaped(value.address);
+      sb.appendHtmlConstant("</div>");
+
+      sb.appendHtmlConstant("</td></tr></table>");
+    }
+
+    /**
+     * By convention, cells that respond to user events should handle the enter
+     * key. This provides a consistent user experience when users use keyboard
+     * navigation in the widget. Our cell will toggle the checkbox on Enter.
+     */
+    @Override
+    protected void onEnterKeyDown(Element parent, Contact value, Object key,
+        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+      // Toggle the checkbox.
+      InputElement input = getInputElement(parent);
+      input.setChecked(!input.isChecked());
+
+      // Update the favorites based on the new state.
+      updateFavorites(parent, value);
+
+      // Show the new list of favorites.
+      showCurrentFavorites();
+    }
+
+    /**
+     * Get the checkbox input element from the parent element that wraps our
+     * cell.
+     * 
+     * @param parent the parent element
+     * @return the checkbox
+     */
+    private InputElement getInputElement(Element parent) {
+      // We need to navigate down to our input element.
+      TableElement table = parent.getFirstChildElement().cast();
+      TableRowElement tr = table.getRows().getItem(0);
+      TableCellElement td = tr.getCells().getItem(0);
+      InputElement input = td.getFirstChildElement().cast();
+      return input;
+    }
+
+    /**
+     * Update the favorites list based on the state of the input element.
+     */
+    private void updateFavorites(Element parent, Contact value) {
+      // Get the input element.
+      InputElement input = getInputElement(parent);
+
+      // Update the favorites based on the checked state.
+      if (input.isChecked()) {
+        favorites.add(value);
+      } else {
+        favorites.remove(value);
+      }
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<Contact> CONTACTS = Arrays.asList(new Contact(
+      "John", "123 Fourth Avenue"), new Contact("Joe", "22 Lance Ln"),
+      new Contact("Michael", "1283 Berry Blvd"), new Contact("Sarah",
+          "100 Hundred St."), new Contact("George", "1600 Pennsylvania Avenue"));
+
+  /**
+   * Our list of favorite contacts.
+   */
+  private final List<Contact> favorites = new ArrayList<EditableCellExample.Contact>();
+
+  public void onModuleLoad() {
+    // Create a cell to render each value.
+    ContactCell contactCell = new ContactCell();
+
+    // Use the cell in a CellList.
+    CellList<Contact> cellList = new CellList<Contact>(contactCell);
+
+    // Push the data into the widget.
+    cellList.setRowData(0, CONTACTS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(cellList);
+  }
+
+  /**
+   * Show the list of favorites.
+   */
+  private void showCurrentFavorites() {
+    if (favorites.size() > 0) {
+      String text = "You favorite contacts are ";
+      boolean first = true;
+      for (Contact contact : favorites) {
+        if (!first) {
+          text += ", ";
+        } else {
+          first = false;
+        }
+        text += contact.name;
+      }
+      Window.alert(text);
+    } else {
+      Window.alert("You have not selected any favorites.");
+    }
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
new file mode 100644
index 0000000..ceaa7a3
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
@@ -0,0 +1,160 @@
+/*
+ * 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.examples.cell;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Example of creating a custom {@link Cell} that responds to events. This
+ * example creates a cell that displays a Contact in a custom format.
+ */
+public class InteractionCellExample implements EntryPoint {
+
+  /**
+   * A simple data type that represents a contact.
+   */
+  private static class Contact {
+    private final String address;
+    private final Date birthday;
+    private final String name;
+
+    public Contact(String name, Date birthday, String address) {
+      this.name = name;
+      this.birthday = birthday;
+      this.address = address;
+    }
+  }
+
+  /**
+   * A custom {@link Cell} used to render a {@link Contact}. We extend
+   * {@link AbstractCell} because it provides reasonable implementations of
+   * methods that work for most use cases.
+   */
+  private static class ContactCell extends AbstractCell<Contact> {
+
+    /**
+     * The {@link DateTimeFormat} used to format the birthday. Since our render
+     * method is called for every value in the list, we want to move heavy
+     * weight work, such as creating a formatter, out of it to speed up
+     * rendering as much as possible.
+     */
+    private DateTimeFormat dateFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG);
+
+    public ContactCell() {
+      /*
+       * Let the parent class know that our cell responds to click events and
+       * keydown events.
+       */
+      super("click", "keydown");
+    }
+
+    @Override
+    public void onBrowserEvent(Element parent, Contact value, Object key,
+        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+      // Check that the value is not null.
+      if (value == null) {
+        return;
+      }
+
+      // Call the super handler, which handlers the enter key.
+      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+
+      // On click, perform the same action that we perform on enter.
+      if ("click".equals(event.getType())) {
+        this.onEnterKeyDown(parent, value, key, event, valueUpdater);
+      }
+    }
+
+    @Override
+    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+      /*
+       * Always do a null check on the value. Cell widgets can pass null to
+       * cells if the underlying data contains a null, or if the data arrives
+       * out of order.
+       */
+      if (value == null) {
+        return;
+      }
+
+      // Display the name in big letters.
+      sb.appendHtmlConstant("<div style=\"size:200%;font-weight:bold;\">");
+      sb.appendEscaped(value.name);
+      sb.appendHtmlConstant("</div>");
+
+      // Display the address in normal text.
+      sb.appendHtmlConstant("<div style=\"padding-left:10px;\">");
+      sb.appendEscaped(value.address);
+      sb.appendHtmlConstant("</div>");
+
+      // Format that birthday and display it in light gray.
+      sb.appendHtmlConstant("<div style=\"padding-left:10px;color:#aaa;\">");
+      sb.append(SafeHtmlUtils.fromTrustedString("Born: "));
+      sb.appendEscaped(dateFormat.format(value.birthday));
+      sb.appendHtmlConstant("</div>");
+    }
+
+    /**
+     * By convention, cells that respond to user events should handle the enter
+     * key. This provides a consistent user experience when users use keyboard
+     * navigation in the widget.
+     */
+    @Override
+    protected void onEnterKeyDown(Element parent, Contact value, Object key,
+        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+      Window.alert("You clicked " + value.name);
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<Contact> CONTACTS = Arrays.asList(new Contact(
+      "John", new Date(80, 4, 12), "123 Fourth Avenue"), new Contact("Joe",
+      new Date(85, 2, 22), "22 Lance Ln"), new Contact("Michael", new Date(80,
+      1, 2), "1283 Berry Blvd"), new Contact("Sarah", new Date(67, 10, 28),
+      "100 Hundred St."), new Contact("George", new Date(46, 6, 6),
+      "1600 Pennsylvania Avenue"));
+
+  public void onModuleLoad() {
+    // Create a cell to render each value.
+    ContactCell contactCell = new ContactCell();
+
+    // Use the cell in a CellList.
+    CellList<Contact> cellList = new CellList<Contact>(contactCell);
+
+    // Push the data into the widget.
+    cellList.setRowData(0, CONTACTS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(cellList);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample.java
new file mode 100644
index 0000000..225f607
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample.java
@@ -0,0 +1,77 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellBrowser;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.TreeViewModel;
+
+/**
+ * Example of {@link CellBrowser}. This example shows a Browser consisting of
+ * strings.
+ */
+public class CellBrowserExample implements EntryPoint {
+
+  /**
+   * The model that defines the nodes in the tree.
+   */
+  private static class CustomTreeModel implements TreeViewModel {
+
+    /**
+     * Get the {@link NodeInfo} that provides the children of the specified
+     * value.
+     */
+    public <T> NodeInfo<?> getNodeInfo(T value) {
+      /*
+       * Create some data in a data provider. Use the parent value as a prefix
+       * for the next level.
+       */
+      ListDataProvider<String> dataProvider = new ListDataProvider<String>();
+      for (int i = 0; i < 2; i++) {
+        dataProvider.getList().add(value + "." + String.valueOf(i));
+      }
+
+      // Return a node info that pairs the data with a cell.
+      return new DefaultNodeInfo<String>(dataProvider, new TextCell());
+    }
+
+    /**
+     * Check if the specified value represents a leaf node. Leaf nodes cannot be
+     * opened.
+     */
+    public boolean isLeaf(Object value) {
+      // The maximum length of a value is ten characters.
+      return value.toString().length() > 10;
+    }
+  }
+
+  public void onModuleLoad() {
+    // Create a model for the browser.
+    TreeViewModel model = new CustomTreeModel();
+
+    /*
+     * Create the browser using the model. We specify the default value of the
+     * hidden root node as "Item 1".
+     */
+    CellBrowser tree = new CellBrowser(model, "Item 1");
+
+    // Add the tree to the root layout panel.
+    RootLayoutPanel.get().add(tree);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
new file mode 100644
index 0000000..af538a9
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
@@ -0,0 +1,278 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellBrowser;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.SingleSelectionModel;
+import com.google.gwt.view.client.TreeViewModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example of {@link CellBrowser}. This example shows a browser consisting of
+ * composers and the compositions they created.
+ */
+public class CellBrowserExample2 implements EntryPoint {
+
+  /**
+   * A list of songs.
+   */
+  private static class Playlist {
+    private final String name;
+    private final List<String> songs = new ArrayList<String>();
+
+    public Playlist(String name) {
+      this.name = name;
+    }
+
+    /**
+     * Add a song to the playlist.
+     * 
+     * @param name the name of the song
+     */
+    public void addSong(String name) {
+      songs.add(name);
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * @return the list of songs in the playlist
+     */
+    public List<String> getSongs() {
+      return songs;
+    }
+  }
+
+  /**
+   * A composer of classical music.
+   */
+  private static class Composer {
+    private final String name;
+    private final List<Playlist> playlists = new ArrayList<Playlist>();
+
+    public Composer(String name) {
+      this.name = name;
+    }
+
+    /**
+     * Add a playlist to the composer.
+     * 
+     * @param playlist the playlist to add
+     */
+    public Playlist addPlaylist(Playlist playlist) {
+      playlists.add(playlist);
+      return playlist;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * @return the rockin' playlist for this composter
+     */
+    public List<Playlist> getPlaylists() {
+      return playlists;
+    }
+  }
+
+  /**
+   * The model that defines the nodes in the tree.
+   */
+  private static class CustomTreeModel implements TreeViewModel {
+
+    private final List<Composer> composers;
+
+    /**
+     * This selection model is shared across all leaf nodes. A selection model
+     * can also be shared across all nodes in the tree, or each set of child
+     * nodes can have its own instance. This gives you flexibility to determine
+     * how nodes are selected.
+     */
+    private final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
+
+    public CustomTreeModel() {
+      // Create a database of information.
+      composers = new ArrayList<Composer>();
+
+      // Add compositions by Beethoven.
+      {
+        Composer beethoven = new Composer("Beethoven");
+        composers.add(beethoven);
+
+        Playlist concertos = beethoven.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("No. 1 - C");
+        concertos.addSong("No. 2 - B-Flat Major");
+        concertos.addSong("No. 3 - C Minor");
+        concertos.addSong("No. 4 - G Major");
+        concertos.addSong("No. 5 - E-Flat Major");
+
+        Playlist quartets = beethoven.addPlaylist(new Playlist("Quartets"));
+        quartets.addSong("Six String Quartets");
+        quartets.addSong("Three String Quartets");
+        quartets.addSong("Grosse Fugue for String Quartets");
+
+        Playlist sonatas = beethoven.addPlaylist(new Playlist("Sonatas"));
+        sonatas.addSong("Sonata in A Minor");
+        sonatas.addSong("Sonata in F Major");
+
+        Playlist symphonies = beethoven.addPlaylist(new Playlist("Symphonies"));
+        symphonies.addSong("No. 2 - D Major");
+        symphonies.addSong("No. 2 - D Major");
+        symphonies.addSong("No. 3 - E-Flat Major");
+        symphonies.addSong("No. 4 - B-Flat Major");
+        symphonies.addSong("No. 5 - C Minor");
+        symphonies.addSong("No. 6 - F Major");
+        symphonies.addSong("No. 7 - A Major");
+        symphonies.addSong("No. 8 - F Major");
+        symphonies.addSong("No. 9 - D Minor");
+      }
+
+      // Add compositions by Brahms.
+      {
+        Composer brahms = new Composer("Brahms");
+        composers.add(brahms);
+        Playlist concertos = brahms.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("Violin Concerto");
+        concertos.addSong("Double Concerto - A Minor");
+        concertos.addSong("Piano Concerto No. 1 - D Minor");
+        concertos.addSong("Piano Concerto No. 2 - B-Flat Major");
+
+        Playlist quartets = brahms.addPlaylist(new Playlist("Quartets"));
+        quartets.addSong("Piano Quartet No. 1 - G Minor");
+        quartets.addSong("Piano Quartet No. 2 - A Major");
+        quartets.addSong("Piano Quartet No. 3 - C Minor");
+        quartets.addSong("String Quartet No. 3 - B-Flat Minor");
+
+        Playlist sonatas = brahms.addPlaylist(new Playlist("Sonatas"));
+        sonatas.addSong("Two Sonatas for Clarinet - F Minor");
+        sonatas.addSong("Two Sonatas for Clarinet - E-Flat Major");
+
+        Playlist symphonies = brahms.addPlaylist(new Playlist("Symphonies"));
+        symphonies.addSong("No. 1 - C Minor");
+        symphonies.addSong("No. 2 - D Minor");
+        symphonies.addSong("No. 3 - F Major");
+        symphonies.addSong("No. 4 - E Minor");
+      }
+
+      // Add compositions by Mozart.
+      {
+        Composer mozart = new Composer("Mozart");
+        composers.add(mozart);
+        Playlist concertos = mozart.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("Piano Concerto No. 12");
+        concertos.addSong("Piano Concerto No. 17");
+        concertos.addSong("Clarinet Concerto");
+        concertos.addSong("Violin Concerto No. 5");
+        concertos.addSong("Violin Concerto No. 4");
+      }
+    }
+
+    /**
+     * Get the {@link NodeInfo} that provides the children of the specified
+     * value.
+     */
+    public <T> NodeInfo<?> getNodeInfo(T value) {
+      if (value == null) {
+        // LEVEL 0.
+        // We passed null as the root value. Return the composers.
+
+        // Create a data provider that contains the list of composers.
+        ListDataProvider<Composer> dataProvider = new ListDataProvider<CellBrowserExample2.Composer>(
+            composers);
+
+        // Create a cell to display a composer.
+        Cell<Composer> cell = new AbstractCell<Composer>() {
+          @Override
+          public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+            if (value != null) {
+              sb.appendEscaped(value.getName());
+            }
+          }
+        };
+
+        // Return a node info that pairs the data provider and the cell.
+        return new DefaultNodeInfo<Composer>(dataProvider, cell);
+      } else if (value instanceof Composer) {
+        // LEVEL 1.
+        // We want the children of the composer. Return the playlists.
+        ListDataProvider<Playlist> dataProvider = new ListDataProvider<Playlist>(
+            ((Composer) value).getPlaylists());
+        Cell<Playlist> cell = new AbstractCell<Playlist>() {
+          @Override
+          public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+            if (value != null) {
+              sb.appendEscaped(value.getName());
+            }
+          }
+        };
+        return new DefaultNodeInfo<Playlist>(dataProvider, cell);
+      } else if (value instanceof Playlist) {
+        // LEVEL 2 - LEAF.
+        // We want the children of the playlist. Return the songs.
+        ListDataProvider<String> dataProvider = new ListDataProvider<String>(
+            ((Playlist) value).getSongs());
+
+        // Use the shared selection model.
+        return new DefaultNodeInfo<String>(dataProvider, new TextCell(),
+            selectionModel, null);
+      }
+
+      return null;
+    }
+
+    /**
+     * Check if the specified value represents a leaf node. Leaf nodes cannot be
+     * opened.
+     */
+    public boolean isLeaf(Object value) {
+      // The leaf nodes are the songs, which are Strings.
+      if (value instanceof String) {
+        return true;
+      }
+      return false;
+    }
+
+  }
+
+  public void onModuleLoad() {
+    // Create a model for the browser.
+    TreeViewModel model = new CustomTreeModel();
+
+    /*
+     * Create the browser using the model. We use <code>null</code> as the
+     * default value of the root node. The default value will be passed to
+     * CustomTreeModel#getNodeInfo();
+     */
+    CellBrowser browser = new CellBrowser(model, null);
+    browser.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+
+    // Add the browser to the root layout panel.
+    RootLayoutPanel.get().add(browser);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellListExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellListExample.java
new file mode 100644
index 0000000..a75b009
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellListExample.java
@@ -0,0 +1,72 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.view.client.SelectionChangeEvent;
+import com.google.gwt.view.client.SingleSelectionModel;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Example of {@link CellList}. This example shows a list of the days of the
+ * week.
+ */
+public class CellListExample implements EntryPoint {
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<String> DAYS = Arrays.asList("Sunday", "Monday",
+      "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
+
+  public void onModuleLoad() {
+    // Create a cell to render each value.
+    TextCell textCell = new TextCell();
+
+    // Create a CellList that uses the cell.
+    CellList<String> cellList = new CellList<String>(textCell);
+    cellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+
+    // Add a selection model to handle user selection.
+    final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
+    cellList.setSelectionModel(selectionModel);
+    selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
+      public void onSelectionChange(SelectionChangeEvent event) {
+        String selected = selectionModel.getSelectedObject();
+        if (selected != null) {
+          Window.alert("You selected: " + selected);
+        }
+      }
+    });
+
+    // Set the total row count. This isn't strictly necessary, but it affects
+    // paging calculations, so its good habit to keep the row count up to date.
+    cellList.setRowCount(DAYS.size(), true);
+
+    // Push the data into the widget.
+    cellList.setRowData(0, DAYS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(cellList);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellListValueUpdaterExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellListValueUpdaterExample.java
new file mode 100644
index 0000000..b700ecc
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellListValueUpdaterExample.java
@@ -0,0 +1,67 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.TextInputCell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Example of using a {@link ValueUpdater} with a {@link CellList}.
+ */
+public class CellListValueUpdaterExample implements EntryPoint {
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<String> DAYS = Arrays.asList("Sunday", "Monday",
+      "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
+
+  public void onModuleLoad() {
+    // Create a cell that will interact with a value updater.
+    TextInputCell inputCell = new TextInputCell();
+
+    // Create a CellList that uses the cell.
+    CellList<String> cellList = new CellList<String>(inputCell);
+
+    // Create a value updater that will be called when the value in a cell
+    // changes.
+    ValueUpdater<String> valueUpdater = new ValueUpdater<String>() {
+      public void update(String newValue) {
+        Window.alert("You typed: " + newValue);
+      }
+    };
+
+    // Add the value updater to the cellList.
+    cellList.setValueUpdater(valueUpdater);
+
+    // Set the total row count. This isn't strictly necessary, but it affects
+    // paging calculations, so its good habit to keep the row count up to date.
+    cellList.setRowCount(DAYS.size(), true);
+
+    // Push the data into the widget.
+    cellList.setRowData(0, DAYS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(cellList);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTableExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellTableExample.java
new file mode 100644
index 0000000..46a7b87
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTableExample.java
@@ -0,0 +1,117 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.DateCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.Column;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.cellview.client.TextColumn;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.view.client.SelectionChangeEvent;
+import com.google.gwt.view.client.SingleSelectionModel;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Example of {@link CellTable}. This example shows a table containing contact
+ * information.
+ */
+public class CellTableExample implements EntryPoint {
+
+  /**
+   * A simple data type that represents a contact.
+   */
+  private static class Contact {
+    private final String address;
+    private final Date birthday;
+    private final String name;
+
+    public Contact(String name, Date birthday, String address) {
+      this.name = name;
+      this.birthday = birthday;
+      this.address = address;
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<Contact> CONTACTS = Arrays.asList(
+      new Contact("John", new Date(80, 4, 12), "123 Fourth Avenue"),
+      new Contact("Joe", new Date(85, 2, 22), "22 Lance Ln"),
+      new Contact("George", new Date(46, 6, 6), "1600 Pennsylvania Avenue"));
+
+  public void onModuleLoad() {
+    // Create a CellTable.
+    CellTable<Contact> table = new CellTable<Contact>();
+    table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+
+    // Add a text column to show the name.
+    TextColumn<Contact> nameColumn = new TextColumn<Contact>() {
+      @Override
+      public String getValue(Contact object) {
+        return object.name;
+      }
+    };
+    table.addColumn(nameColumn, "Name");
+
+    // Add a date column to show the birthday.
+    DateCell dateCell = new DateCell();
+    Column<Contact, Date> dateColumn = new Column<Contact, Date>(dateCell) {
+      @Override
+      public Date getValue(Contact object) {
+        return object.birthday;
+      }
+    };
+    table.addColumn(dateColumn, "Birthday");
+
+    // Add a text column to show the address.
+    TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
+      @Override
+      public String getValue(Contact object) {
+        return object.address;
+      }
+    };
+    table.addColumn(addressColumn, "Address");
+
+    // Add a selection model to handle user selection.
+    final SingleSelectionModel<Contact> selectionModel = new SingleSelectionModel<Contact>();
+    table.setSelectionModel(selectionModel);
+    selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
+      public void onSelectionChange(SelectionChangeEvent event) {
+        Contact selected = selectionModel.getSelectedObject();
+        if (selected != null) {
+          Window.alert("You selected: " + selected.name);
+        }
+      }
+    });
+
+    // Set the total row count. This isn't strictly necessary, but it affects
+    // paging calculations, so its good habit to keep the row count up to date.
+    table.setRowCount(CONTACTS.size(), true);
+
+    // Push the data into the widget.
+    table.setRowData(0, CONTACTS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(table);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTableFieldUpdaterExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellTableFieldUpdaterExample.java
new file mode 100644
index 0000000..5ef66b7
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTableFieldUpdaterExample.java
@@ -0,0 +1,171 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.DatePickerCell;
+import com.google.gwt.cell.client.FieldUpdater;
+import com.google.gwt.cell.client.TextInputCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.Column;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.cellview.client.TextColumn;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.view.client.ProvidesKey;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Example of using a {@link FieldUpdater} with a {@link CellTable}.
+ */
+public class CellTableFieldUpdaterExample implements EntryPoint {
+
+  /**
+   * A simple data type that represents a contact with a unique ID.
+   */
+  private static class Contact {
+    private static int nextId = 0;
+
+    private final int id;
+    private final String address;
+    private Date birthday;
+    private String name;
+
+    public Contact(String name, Date birthday, String address) {
+      nextId++;
+      this.id = nextId;
+      this.name = name;
+      this.birthday = birthday;
+      this.address = address;
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<Contact> CONTACTS = Arrays.asList(
+      new Contact("John", new Date(80, 4, 12), "123 Fourth Avenue"),
+      new Contact("Joe", new Date(85, 2, 22), "22 Lance Ln"),
+      new Contact("George", new Date(46, 6, 6), "1600 Pennsylvania Avenue"));
+
+  /**
+   * The key provider that allows us to identify Contacts even if a field
+   * changes. We identify contacts by their unique ID.
+   */
+  private static final ProvidesKey<Contact> KEY_PROVIDER = new ProvidesKey<CellTableFieldUpdaterExample.Contact>() {
+    public Object getKey(Contact item) {
+      return item.id;
+    }
+  };
+
+  public void onModuleLoad() {
+    // Create a CellTable with a key provider.
+    final CellTable<Contact> table = new CellTable<Contact>(KEY_PROVIDER);
+    table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+
+    // Add a text input column to edit the name.
+    final TextInputCell nameCell = new TextInputCell();
+    Column<Contact, String> nameColumn = new Column<Contact, String>(nameCell) {
+      @Override
+      public String getValue(Contact object) {
+        return object.name;
+      }
+    };
+    table.addColumn(nameColumn, "Name");
+
+    // Add a field updater to be notified when the user enters a new name.
+    nameColumn.setFieldUpdater(new FieldUpdater<Contact, String>() {
+      public void update(int index, Contact object, String value) {
+        // Validate the data.
+        if (value.length() < 3) {
+          Window.alert("Names must be at least three characters long.");
+
+          /*
+           * Clear the view data. The view data contains the pending change and
+           * allows the table to render with the pending value until the data is
+           * committed. If the data is committed into the object, the view data
+           * is automatically cleared out. If the data is not committed because
+           * it is invalid, you must delete.
+           */
+          nameCell.clearViewData(KEY_PROVIDER.getKey(object));
+
+          // Redraw the table.
+          table.redraw();
+          return;
+        }
+
+        // Inform the user of the change.
+        Window.alert("You changed the name of " + object.name + " to " + value);
+
+        // Push the changes into the Contact. At this point, you could send an
+        // asynchronous request to the server to update the database.
+        object.name = value;
+
+        // Redraw the table with the new data.
+        table.redraw();
+      }
+    });
+
+    // Add a date column to show the birthday.
+    Column<Contact, Date> dateColumn = new Column<Contact, Date>(
+        new DatePickerCell()) {
+      @Override
+      public Date getValue(Contact object) {
+        return object.birthday;
+      }
+    };
+    table.addColumn(dateColumn, "Birthday");
+
+    // Add a field updater to be notified when the user enters a new birthday.
+    dateColumn.setFieldUpdater(new FieldUpdater<Contact, Date>() {
+      public void update(int index, Contact object, Date value) {
+        Window.alert("You changed the birthday of "
+            + object.name
+            + " to "
+            + DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG).format(value));
+
+        // Push the changes into the Contact.
+        object.birthday = value;
+
+        // Redraw the table with the new data.
+        table.redraw();
+      }
+    });
+    // Add a text column to show the address.
+    TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
+      @Override
+      public String getValue(Contact object) {
+        return object.address;
+      }
+    };
+    table.addColumn(addressColumn, "Address");
+
+    // Set the total row count. This isn't strictly necessary, but it affects
+    // paging calculations, so its good habit to keep the row count up to date.
+    table.setRowCount(CONTACTS.size(), true);
+
+    // Push the data into the widget.
+    table.setRowData(0, CONTACTS);
+
+    // Add it to the root panel.
+    RootPanel.get().add(table);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample.java b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample.java
new file mode 100644
index 0000000..777baa2
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample.java
@@ -0,0 +1,76 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellTree;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.TreeViewModel;
+
+/**
+ * Example of {@link CellTree}. This example shows a Tree consisting of strings.
+ */
+public class CellTreeExample implements EntryPoint {
+
+  /**
+   * The model that defines the nodes in the tree.
+   */
+  private static class CustomTreeModel implements TreeViewModel {
+
+    /**
+     * Get the {@link NodeInfo} that provides the children of the specified
+     * value.
+     */
+    public <T> NodeInfo<?> getNodeInfo(T value) {
+      /*
+       * Create some data in a data provider. Use the parent value as a prefix
+       * for the next level.
+       */
+      ListDataProvider<String> dataProvider = new ListDataProvider<String>();
+      for (int i = 0; i < 2; i++) {
+        dataProvider.getList().add(value + "." + String.valueOf(i));
+      }
+
+      // Return a node info that pairs the data with a cell.
+      return new DefaultNodeInfo<String>(dataProvider, new TextCell());
+    }
+
+    /**
+     * Check if the specified value represents a leaf node. Leaf nodes cannot be
+     * opened.
+     */
+    public boolean isLeaf(Object value) {
+      // The maximum length of a value is ten characters.
+      return value.toString().length() > 10;
+    }
+  }
+
+  public void onModuleLoad() {
+    // Create a model for the tree.
+    TreeViewModel model = new CustomTreeModel();
+
+    /*
+     * Create the tree using the model. We specify the default value of the
+     * hidden root node as "Item 1".
+     */
+    CellTree tree = new CellTree(model, "Item 1");
+
+    // Add the tree to the root layout panel.
+    RootLayoutPanel.get().add(tree);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
new file mode 100644
index 0000000..f51dbec
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
@@ -0,0 +1,284 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellTree;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.cellview.client.TreeNode;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.SingleSelectionModel;
+import com.google.gwt.view.client.TreeViewModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example of {@link CellTree}. This example shows a Tree consisting of
+ * composers and the compositions they created.
+ */
+public class CellTreeExample2 implements EntryPoint {
+
+  /**
+   * A list of songs.
+   */
+  private static class Playlist {
+    private final String name;
+    private final List<String> songs = new ArrayList<String>();
+
+    public Playlist(String name) {
+      this.name = name;
+    }
+
+    /**
+     * Add a song to the playlist.
+     * 
+     * @param name the name of the song
+     */
+    public void addSong(String name) {
+      songs.add(name);
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * @return the list of songs in the playlist
+     */
+    public List<String> getSongs() {
+      return songs;
+    }
+  }
+
+  /**
+   * A composer of classical music.
+   */
+  private static class Composer {
+    private final String name;
+    private final List<Playlist> playlists = new ArrayList<Playlist>();
+
+    public Composer(String name) {
+      this.name = name;
+    }
+
+    /**
+     * Add a playlist to the composer.
+     * 
+     * @param playlist the playlist to add
+     */
+    public Playlist addPlaylist(Playlist playlist) {
+      playlists.add(playlist);
+      return playlist;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * @return the rockin' playlist for this composter
+     */
+    public List<Playlist> getPlaylists() {
+      return playlists;
+    }
+  }
+
+  /**
+   * The model that defines the nodes in the tree.
+   */
+  private static class CustomTreeModel implements TreeViewModel {
+
+    private final List<Composer> composers;
+
+    /**
+     * This selection model is shared across all leaf nodes. A selection model
+     * can also be shared across all nodes in the tree, or each set of child
+     * nodes can have its own instance. This gives you flexibility to determine
+     * how nodes are selected.
+     */
+    private final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
+
+    public CustomTreeModel() {
+      // Create a database of information.
+      composers = new ArrayList<Composer>();
+
+      // Add compositions by Beethoven.
+      {
+        Composer beethoven = new Composer("Beethoven");
+        composers.add(beethoven);
+
+        Playlist concertos = beethoven.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("No. 1 - C");
+        concertos.addSong("No. 2 - B-Flat Major");
+        concertos.addSong("No. 3 - C Minor");
+        concertos.addSong("No. 4 - G Major");
+        concertos.addSong("No. 5 - E-Flat Major");
+
+        Playlist quartets = beethoven.addPlaylist(new Playlist("Quartets"));
+        quartets.addSong("Six String Quartets");
+        quartets.addSong("Three String Quartets");
+        quartets.addSong("Grosse Fugue for String Quartets");
+
+        Playlist sonatas = beethoven.addPlaylist(new Playlist("Sonatas"));
+        sonatas.addSong("Sonata in A Minor");
+        sonatas.addSong("Sonata in F Major");
+
+        Playlist symphonies = beethoven.addPlaylist(new Playlist("Symphonies"));
+        symphonies.addSong("No. 2 - D Major");
+        symphonies.addSong("No. 2 - D Major");
+        symphonies.addSong("No. 3 - E-Flat Major");
+        symphonies.addSong("No. 4 - B-Flat Major");
+        symphonies.addSong("No. 5 - C Minor");
+        symphonies.addSong("No. 6 - F Major");
+        symphonies.addSong("No. 7 - A Major");
+        symphonies.addSong("No. 8 - F Major");
+        symphonies.addSong("No. 9 - D Minor");
+      }
+
+      // Add compositions by Brahms.
+      {
+        Composer brahms = new Composer("Brahms");
+        composers.add(brahms);
+        Playlist concertos = brahms.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("Violin Concerto");
+        concertos.addSong("Double Concerto - A Minor");
+        concertos.addSong("Piano Concerto No. 1 - D Minor");
+        concertos.addSong("Piano Concerto No. 2 - B-Flat Major");
+
+        Playlist quartets = brahms.addPlaylist(new Playlist("Quartets"));
+        quartets.addSong("Piano Quartet No. 1 - G Minor");
+        quartets.addSong("Piano Quartet No. 2 - A Major");
+        quartets.addSong("Piano Quartet No. 3 - C Minor");
+        quartets.addSong("String Quartet No. 3 - B-Flat Minor");
+
+        Playlist sonatas = brahms.addPlaylist(new Playlist("Sonatas"));
+        sonatas.addSong("Two Sonatas for Clarinet - F Minor");
+        sonatas.addSong("Two Sonatas for Clarinet - E-Flat Major");
+
+        Playlist symphonies = brahms.addPlaylist(new Playlist("Symphonies"));
+        symphonies.addSong("No. 1 - C Minor");
+        symphonies.addSong("No. 2 - D Minor");
+        symphonies.addSong("No. 3 - F Major");
+        symphonies.addSong("No. 4 - E Minor");
+      }
+
+      // Add compositions by Mozart.
+      {
+        Composer mozart = new Composer("Mozart");
+        composers.add(mozart);
+        Playlist concertos = mozart.addPlaylist(new Playlist("Concertos"));
+        concertos.addSong("Piano Concerto No. 12");
+        concertos.addSong("Piano Concerto No. 17");
+        concertos.addSong("Clarinet Concerto");
+        concertos.addSong("Violin Concerto No. 5");
+        concertos.addSong("Violin Concerto No. 4");
+      }
+    }
+
+    /**
+     * Get the {@link NodeInfo} that provides the children of the specified
+     * value.
+     */
+    public <T> NodeInfo<?> getNodeInfo(T value) {
+      if (value == null) {
+        // LEVEL 0.
+        // We passed null as the root value. Return the composers.
+
+        // Create a data provider that contains the list of composers.
+        ListDataProvider<Composer> dataProvider = new ListDataProvider<CellTreeExample2.Composer>(
+            composers);
+
+        // Create a cell to display a composer.
+        Cell<Composer> cell = new AbstractCell<Composer>() {
+          @Override
+          public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+            if (value != null) {
+              sb.appendEscaped(value.getName());
+            }
+          }
+        };
+
+        // Return a node info that pairs the data provider and the cell.
+        return new DefaultNodeInfo<Composer>(dataProvider, cell);
+      } else if (value instanceof Composer) {
+        // LEVEL 1.
+        // We want the children of the composer. Return the playlists.
+        ListDataProvider<Playlist> dataProvider = new ListDataProvider<Playlist>(
+            ((Composer) value).getPlaylists());
+        Cell<Playlist> cell = new AbstractCell<Playlist>() {
+          @Override
+          public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+            if (value != null) {
+              sb.appendEscaped(value.getName());
+            }
+          }
+        };
+        return new DefaultNodeInfo<Playlist>(dataProvider, cell);
+      } else if (value instanceof Playlist) {
+        // LEVEL 2 - LEAF.
+        // We want the children of the playlist. Return the songs.
+        ListDataProvider<String> dataProvider = new ListDataProvider<String>(
+            ((Playlist) value).getSongs());
+
+        // Use the shared selection model.
+        return new DefaultNodeInfo<String>(dataProvider, new TextCell(),
+            selectionModel, null);
+      }
+
+      return null;
+    }
+
+    /**
+     * Check if the specified value represents a leaf node. Leaf nodes cannot be
+     * opened.
+     */
+    public boolean isLeaf(Object value) {
+      // The leaf nodes are the songs, which are Strings.
+      if (value instanceof String) {
+        return true;
+      }
+      return false;
+    }
+
+  }
+
+  public void onModuleLoad() {
+    // Create a model for the tree.
+    TreeViewModel model = new CustomTreeModel();
+
+    /*
+     * Create the tree using the model. We use <code>null</code> as the default
+     * value of the root node. The default value will be passed to
+     * CustomTreeModel#getNodeInfo();
+     */
+    CellTree tree = new CellTree(model, null);
+    tree.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+
+    // Open the first playlist by default.
+    TreeNode rootNode = tree.getRootTreeNode();
+    TreeNode firstPlaylist = rootNode.setChildOpen(0, true);
+    firstPlaylist.setChildOpen(0, true);
+
+    // Add the tree to the root layout panel.
+    RootLayoutPanel.get().add(tree);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/SimplePagerExample.java b/user/javadoc/com/google/gwt/examples/cellview/SimplePagerExample.java
new file mode 100644
index 0000000..26c272a
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/cellview/SimplePagerExample.java
@@ -0,0 +1,57 @@
+/*
+ * 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.examples.cellview;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.cellview.client.SimplePager;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.view.client.ListDataProvider;
+
+import java.util.List;
+
+/**
+ * Example of {@link SimplePager}.
+ */
+public class SimplePagerExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    // Create a CellList.
+    CellList<String> cellList = new CellList<String>(new TextCell());
+
+    // Add a cellList to a data provider.
+    ListDataProvider<String> dataProvider = new ListDataProvider<String>();
+    List<String> data = dataProvider.getList();
+    for (int i = 0; i < 200; i++) {
+      data.add("Item " + i);
+    }
+    dataProvider.addDataDisplay(cellList);
+
+    // Create a SimplePager.
+    SimplePager pager = new SimplePager();
+
+    // Set the cellList as the display.
+    pager.setDisplay(cellList);
+
+    // Add the pager and list to the page.
+    VerticalPanel vPanel = new VerticalPanel();
+    vPanel.add(pager);
+    vPanel.add(cellList);
+    RootPanel.get().add(vPanel);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/view/AsyncDataProviderExample.java b/user/javadoc/com/google/gwt/examples/view/AsyncDataProviderExample.java
new file mode 100644
index 0000000..dea6fd6
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/view/AsyncDataProviderExample.java
@@ -0,0 +1,95 @@
+/*
+ * 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.examples.view;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.cellview.client.SimplePager;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.view.client.AsyncDataProvider;
+import com.google.gwt.view.client.HasData;
+import com.google.gwt.view.client.Range;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example of {@link AsyncDataProvider}.
+ */
+public class AsyncDataProviderExample implements EntryPoint {
+
+  /**
+   * A custom {@link AsyncDataProvider}.
+   */
+  private static class MyDataProvider extends AsyncDataProvider<String> {
+    /**
+     * {@link #onRangeChanged(HasData)} is called when the table requests a new
+     * range of data. You can push data back to the displays using
+     * {@link #updateRowData(int, List)}.
+     */
+    @Override
+    protected void onRangeChanged(HasData<String> display) {
+      // Get the new range.
+      final Range range = display.getVisibleRange();
+
+      /*
+       * Query the data asynchronously. If you are using a database, you can
+       * make an RPC call here. We'll use a Timer to simulate a delay.
+       */
+      new Timer() {
+        @Override
+        public void run() {
+          // We are creating fake data. Normally, the data will come from a
+          // server.
+          int start = range.getStart();
+          int length = range.getLength();
+          List<String> newData = new ArrayList<String>();
+          for (int i = start; i < start + length; i++) {
+            newData.add("Item " + i);
+          }
+
+          // Push the data to the displays. AsyncDataProvider will only update
+          // displays that are within range of the data.
+          updateRowData(start, newData);
+        }
+      }.schedule(3000);
+    }
+  }
+
+  public void onModuleLoad() {
+    // Create a CellList.
+    CellList<String> cellList = new CellList<String>(new TextCell());
+
+    // Create a data provider.
+    MyDataProvider dataProvider = new MyDataProvider();
+
+    // Add the cellList to the dataProvider.
+    dataProvider.addDataDisplay(cellList);
+
+    // Create paging controls.
+    SimplePager pager = new SimplePager();
+    pager.setDisplay(cellList);
+
+    // Add the widgets to the root panel.
+    VerticalPanel vPanel = new VerticalPanel();
+    vPanel.add(pager);
+    vPanel.add(cellList);
+    RootPanel.get().add(vPanel);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
new file mode 100644
index 0000000..f3cfc89
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
@@ -0,0 +1,116 @@
+/*
+ * 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.examples.view;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.view.client.ProvidesKey;
+import com.google.gwt.view.client.SelectionModel;
+import com.google.gwt.view.client.SingleSelectionModel;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Example of using a {@link ProvidesKey}.
+ */
+public class KeyProviderExample implements EntryPoint {
+
+  /**
+   * A simple data type that represents a contact.
+   */
+  private static class Contact {
+    private static int nextId = 0;
+
+    private final int id;
+    private String name;
+
+    public Contact(String name) {
+      nextId++;
+      this.id = nextId;
+      this.name = name;
+    }
+  }
+
+  /**
+   * A custom {@link Cell} used to render a {@link Contact}.
+   */
+  private static class ContactCell extends AbstractCell<Contact> {
+    @Override
+    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+      if (value != null) {
+        sb.appendEscaped(value.name);
+      }
+    }
+  }
+
+  /**
+   * The list of data to display.
+   */
+  private static final List<Contact> CONTACTS = Arrays.asList(new Contact(
+      "John"), new Contact("Joe"), new Contact("Michael"),
+      new Contact("Sarah"), new Contact("George"));
+
+  public void onModuleLoad() {
+    /*
+     * Define a key provider for a Contact. We use the unique ID as the key,
+     * which allows to maintain selection even if the name changes.
+     */
+    ProvidesKey<Contact> keyProvider = new ProvidesKey<Contact>() {
+      public Object getKey(Contact item) {
+        // Always do a null check.
+        return (item == null) ? null : item.id;
+      }
+    };
+
+    // Create a CellList using the keyProvider.
+    CellList<Contact> cellList = new CellList<Contact>(new ContactCell(),
+        keyProvider);
+
+    // Push data into the CellList.
+    cellList.setRowCount(CONTACTS.size(), true);
+    cellList.setRowData(0, CONTACTS);
+
+    // Add a selection model using the same keyProvider.
+    SelectionModel<Contact> selectionModel = new SingleSelectionModel<Contact>(
+        keyProvider);
+    cellList.setSelectionModel(selectionModel);
+
+    /*
+     * Select a contact. The selectionModel will select based on the ID because
+     * we used a keyProvider.
+     */
+    Contact sarah = CONTACTS.get(3);
+    selectionModel.setSelected(sarah, true);
+
+    // Modify the name of the contact.
+    sarah.name = "Sara";
+
+    /*
+     * Redraw the CellList. Sarah/Sara will still be selected because we
+     * identify her by ID. If we did not use a keyProvider, Sara would not be
+     * selected.
+     */
+    cellList.redraw();
+
+    // Add the widgets to the root panel.
+    RootPanel.get().add(cellList);
+  }
+}
\ No newline at end of file
diff --git a/user/javadoc/com/google/gwt/examples/view/ListDataProviderExample.java b/user/javadoc/com/google/gwt/examples/view/ListDataProviderExample.java
new file mode 100644
index 0000000..faf6c5a
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/view/ListDataProviderExample.java
@@ -0,0 +1,69 @@
+/*
+ * 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.examples.view;
+
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.view.client.ListDataProvider;
+
+import java.util.List;
+
+/**
+ * Example of {@link ListDataProvider}.
+ */
+public class ListDataProviderExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    // Create a CellList.
+    CellList<String> cellList = new CellList<String>(new TextCell());
+
+    // Create a list data provider.
+    final ListDataProvider<String> dataProvider = new ListDataProvider<String>();
+
+    // Add the cellList to the dataProvider.
+    dataProvider.addDataDisplay(cellList);
+
+    // Create a form to add values to the data provider.
+    final TextBox valueBox = new TextBox();
+    valueBox.setText("Enter new value");
+    Button addButton = new Button("Add value", new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        // Get the value from the text box.
+        String newValue = valueBox.getText();
+
+        // Get the underlying list from data dataProvider.
+        List<String> list = dataProvider.getList();
+
+        // Add the value to the list. The dataProvider will update the cellList.
+        list.add(newValue);
+      }
+    });
+
+    // Add the widgets to the root panel.
+    VerticalPanel vPanel = new VerticalPanel();
+    vPanel.add(valueBox);
+    vPanel.add(addButton);
+    vPanel.add(cellList);
+    RootPanel.get().add(vPanel);
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/activity/Activity.gwt.xml b/user/src/com/google/gwt/activity/Activity.gwt.xml
new file mode 100644
index 0000000..78b19d0
--- /dev/null
+++ b/user/src/com/google/gwt/activity/Activity.gwt.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
+<module>
+  <inherits name='com.google.gwt.user.User'/>
+  <inherits name='com.google.gwt.place.Place'/>
+
+  <source path="shared"/>
+</module>
diff --git a/user/src/com/google/gwt/app/place/AbstractActivity.java b/user/src/com/google/gwt/activity/shared/AbstractActivity.java
similarity index 96%
rename from user/src/com/google/gwt/app/place/AbstractActivity.java
rename to user/src/com/google/gwt/activity/shared/AbstractActivity.java
index 90c8777..a4cfd70 100644
--- a/user/src/com/google/gwt/app/place/AbstractActivity.java
+++ b/user/src/com/google/gwt/activity/shared/AbstractActivity.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
 
 /**
  * <p>
diff --git a/user/src/com/google/gwt/app/place/Activity.java b/user/src/com/google/gwt/activity/shared/Activity.java
similarity index 89%
rename from user/src/com/google/gwt/app/place/Activity.java
rename to user/src/com/google/gwt/activity/shared/Activity.java
index 30590c4..e092e3f 100644
--- a/user/src/com/google/gwt/app/place/Activity.java
+++ b/user/src/com/google/gwt/activity/shared/Activity.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
 
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
@@ -26,7 +26,8 @@
  * </p>
  * Implemented by objects that control a piece of user interface, with a life
  * cycle managed by an {@link ActivityManager}, in response to
- * {@link PlaceChangeEvent} events as the user navigates through the app.
+ * {@link com.google.gwt.place.shared.PlaceChangeEvent} events as the user
+ * navigates through the app.
  */
 public interface Activity {
   /**
@@ -52,8 +53,8 @@
   /**
    * Called when the Activity should ready its widget for the user. When the
    * widget is ready (typically after an RPC response has been received),
-   * receiver should present it by calling
-   * {@link AcceptsOneWidget#setWidget()} on the given panel
+   * receiver should present it by calling {@link AcceptsOneWidget#setWidget()}
+   * on the given panel.
    * <p>
    * Any handlers attached to the provided event bus will be de-registered when
    * the activity is stopped, so activities will rarely need to hold on to the
diff --git a/user/src/com/google/gwt/app/place/ActivityManager.java b/user/src/com/google/gwt/activity/shared/ActivityManager.java
similarity index 95%
rename from user/src/com/google/gwt/app/place/ActivityManager.java
rename to user/src/com/google/gwt/activity/shared/ActivityManager.java
index f3577ff..30626bf 100644
--- a/user/src/com/google/gwt/app/place/ActivityManager.java
+++ b/user/src/com/google/gwt/activity/shared/ActivityManager.java
@@ -13,12 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
 
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.event.shared.ResettableEventBus;
 import com.google.gwt.event.shared.UmbrellaException;
+import com.google.gwt.place.shared.PlaceChangeEvent;
+import com.google.gwt.place.shared.PlaceChangeRequestEvent;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 import com.google.gwt.user.client.ui.IsWidget;
 
@@ -77,8 +79,9 @@
 
   /**
    * Create an ActivityManager. Next call {@link #setDisplay}.
-   *
-   * @param mapper finds the {@link Activity} for a given {@link Place}
+   * 
+   * @param mapper finds the {@link Activity} for a given
+   *          {@link com.google.gwt.place.shared.Place}
    * @param eventBus source of {@link PlaceChangeEvent} and
    *          {@link PlaceChangeRequestEvent} events.
    */
diff --git a/user/src/com/google/gwt/app/place/ActivityMapper.java b/user/src/com/google/gwt/activity/shared/ActivityMapper.java
similarity index 91%
rename from user/src/com/google/gwt/app/place/ActivityMapper.java
rename to user/src/com/google/gwt/activity/shared/ActivityMapper.java
index 114295b..d7fce27 100644
--- a/user/src/com/google/gwt/app/place/ActivityMapper.java
+++ b/user/src/com/google/gwt/activity/shared/ActivityMapper.java
@@ -13,7 +13,9 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
+
+import com.google.gwt.place.shared.Place;
 
 /**
  * <p>
diff --git a/user/src/com/google/gwt/app/place/CachingActivityMapper.java b/user/src/com/google/gwt/activity/shared/CachingActivityMapper.java
similarity index 93%
rename from user/src/com/google/gwt/app/place/CachingActivityMapper.java
rename to user/src/com/google/gwt/activity/shared/CachingActivityMapper.java
index 2b234c3..a651649 100644
--- a/user/src/com/google/gwt/app/place/CachingActivityMapper.java
+++ b/user/src/com/google/gwt/activity/shared/CachingActivityMapper.java
@@ -13,7 +13,9 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
+
+import com.google.gwt.place.shared.Place;
 
 /**
  * Wraps another {@link ActivityMapper} and caches the last activity it
diff --git a/user/src/com/google/gwt/app/place/FilteredActivityMapper.java b/user/src/com/google/gwt/activity/shared/FilteredActivityMapper.java
similarity index 81%
rename from user/src/com/google/gwt/app/place/FilteredActivityMapper.java
rename to user/src/com/google/gwt/activity/shared/FilteredActivityMapper.java
index 1ba484d..16b774c 100644
--- a/user/src/com/google/gwt/app/place/FilteredActivityMapper.java
+++ b/user/src/com/google/gwt/activity/shared/FilteredActivityMapper.java
@@ -1,39 +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.app.place;
+package com.google.gwt.activity.shared;
+
+import com.google.gwt.place.shared.Place;
 
 /**
- * Wraps an activity mapper and applies a filter to the place objects 
- * that it sees.
+ * Wraps an activity mapper and applies a filter to the place objects that it
+ * sees.
  */
 public class FilteredActivityMapper implements ActivityMapper {
-  interface Filter {
+
+  /**
+   * Implemented by objects that want to interpret one place as another.
+   */
+  public interface Filter {
     Place filter(Place place);
   }
-  
+
   private final Filter filter;
   private final ActivityMapper wrapped;
-  
+
   public FilteredActivityMapper(Filter filter, ActivityMapper wrapped) {
     this.filter = filter;
     this.wrapped = wrapped;
   }
-  
+
   public Activity getActivity(Place place) {
     return wrapped.getActivity(filter.filter(place));
   }
-
 }
diff --git a/user/src/com/google/gwt/app/App.gwt.xml b/user/src/com/google/gwt/app/App.gwt.xml
deleted file mode 100644
index 377ad4a..0000000
--- a/user/src/com/google/gwt/app/App.gwt.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
-<module>
-  <inherits name='com.google.gwt.user.User'/>
-  <inherits name='com.google.gwt.requestfactory.RequestFactory'/>
-
-  <source path="place"/>
-  <source path="client"/>
-  <generate-with class="com.google.gwt.app.rebind.PlaceHistoryMapperGenerator">
-    <when-type-assignable class="com.google.gwt.app.place.PlaceHistoryMapper"/>
-  </generate-with>
-</module>
diff --git a/user/src/com/google/gwt/app/client/BooleanParser.java b/user/src/com/google/gwt/app/client/BooleanParser.java
deleted file mode 100644
index d9f064c..0000000
--- a/user/src/com/google/gwt/app/client/BooleanParser.java
+++ /dev/null
@@ -1,47 +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.app.client;
-
-import com.google.gwt.text.shared.Parser;
-
-/**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * An unlocalized simple parser based on {@link Boolean#valueOf}.
- */
-public class BooleanParser implements Parser<Boolean> {
-
-  private static BooleanParser INSTANCE;
-
-  /**
-   * @return the instance of the no-op renderer
-   */
-  public static Parser<Boolean> instance() {
-    if (INSTANCE == null) {
-      INSTANCE = new BooleanParser();
-    }
-    return INSTANCE;
-  }
-
-  protected BooleanParser() {
-  }
-
-  public Boolean parse(CharSequence object) {
-    return Boolean.valueOf(object.toString());
-  }
-}
diff --git a/user/src/com/google/gwt/app/client/BooleanRenderer.java b/user/src/com/google/gwt/app/client/BooleanRenderer.java
deleted file mode 100644
index 9ffea3b..0000000
--- a/user/src/com/google/gwt/app/client/BooleanRenderer.java
+++ /dev/null
@@ -1,47 +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.app.client;
-
-import com.google.gwt.text.shared.AbstractRenderer;
-import com.google.gwt.text.shared.Renderer;
-
-/**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * Simple unlocalized renderer of Boolean values.
- */
-public class BooleanRenderer extends AbstractRenderer<Boolean> {
-  private static BooleanRenderer INSTANCE;
-
-  /**
-   * @return the instance
-   */
-  public static Renderer<Boolean> instance() {
-    if (INSTANCE == null) {
-      INSTANCE = new BooleanRenderer();
-    }
-    return INSTANCE;
-  }
-
-  protected BooleanRenderer() {
-  }
-
-  public String render(Boolean object) {
-    return toString(object);
-  }
-}
diff --git a/user/src/com/google/gwt/app/client/package.html b/user/src/com/google/gwt/app/client/package.html
deleted file mode 100644
index 9f3bac1..0000000
--- a/user/src/com/google/gwt/app/client/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
-<body>
-Client specific classes of the GWT application framework.
-
-<p><span style="color:red">Experimental API: All classes in this package are still under rapid development, and are very likely to be deleted or renamed. Use them at your own risk.
-</span></p>
-</body>
-</html>
diff --git a/user/src/com/google/gwt/app/package.html b/user/src/com/google/gwt/app/package.html
deleted file mode 100644
index c7deb8d..0000000
--- a/user/src/com/google/gwt/app/package.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-<body>
-Classes that frame an application architecture.
-
-<p><span style="color:red">Experimental API: All classes in this package are still under rapid development, and are very likely to be deleted or renamed. Use them at your own risk.
-</span></p>
-
-</body>
-</html>
diff --git a/user/src/com/google/gwt/app/place/package.html b/user/src/com/google/gwt/app/place/package.html
deleted file mode 100644
index f10479d..0000000
--- a/user/src/com/google/gwt/app/place/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<body>
-Classes to define application workflow.
-<p><span style="color:red">Experimental API: All classes in this package are still under rapid development, and are very likely to be deleted or renamed. Use them at your own risk.
-</span></p>
-</body>
-</html>
diff --git a/user/src/com/google/gwt/cell/client/AbstractCell.java b/user/src/com/google/gwt/cell/client/AbstractCell.java
index 9bfa026..121d36b 100644
--- a/user/src/com/google/gwt/cell/client/AbstractCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractCell.java
@@ -28,7 +28,15 @@
  * A default implementation of the {@link Cell} interface.
  *
  * <p>
- * Note: This class is new and its interface subject to change.
+ * <h3>Examples</h3>
+ * <dl>
+ * <dt>Read only cell</dt>
+ * <dd>TODO example com.google.gwt.examples.cell.CellExample</dd>
+ * <dt>Interactive cell</dt>
+ * <dd>TODO example com.google.gwt.examples.cell.InteractionCellExample</dd>
+ * <dt>Editable cell</dt>
+ * <dd>TODO example com.google.gwt.examples.cell.EditableCellExample</dd>
+ * </dl>
  * </p>
  *
  * @param <C> the type that this Cell represents
diff --git a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
index b115413..90c26f9 100644
--- a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
@@ -26,7 +26,8 @@
  * cells that need to save view data state for specific values.
  *
  * <p>
- * Note: This class is new and its interface subject to change.
+ * <h3>Example</h3>
+ * TODO example com.google.gwt.examples.cell.EditableCellExample
  * </p>
  *
  * @param <C> the type that this Cell represents
diff --git a/user/src/com/google/gwt/cell/client/Cell.java b/user/src/com/google/gwt/cell/client/Cell.java
index bbe169b..12306f4 100644
--- a/user/src/com/google/gwt/cell/client/Cell.java
+++ b/user/src/com/google/gwt/cell/client/Cell.java
@@ -25,7 +25,8 @@
  * A light weight representation of a renderable object.
  *
  * <p>
- * Note: This class is new and its interface subject to change.
+ * <h3>Example</h3>
+ * TODO example com.google.gwt.examples.cell.CellExample
  * </p>
  *
  * @param <C> the type that this Cell represents
diff --git a/user/src/com/google/gwt/editor/Editor.gwt.xml b/user/src/com/google/gwt/editor/Editor.gwt.xml
index 3720f24..adda3ed 100644
--- a/user/src/com/google/gwt/editor/Editor.gwt.xml
+++ b/user/src/com/google/gwt/editor/Editor.gwt.xml
@@ -14,10 +14,14 @@
 <!-- Editor framework support -->
 <module>
   <inherits name="com.google.gwt.core.Core" />
+  
+  <source path="client"/>
+  <source path="ui/client"/>
+  
   <generate-with class="com.google.gwt.editor.rebind.AutoBeanFactoryGenerator">
     <when-type-assignable class="com.google.gwt.editor.client.AutoBeanFactory" />
   </generate-with>
   <generate-with class="com.google.gwt.editor.rebind.SimpleBeanEditorDriverGenerator">
     <when-type-assignable class="com.google.gwt.editor.client.SimpleBeanEditorDriver" />
   </generate-with>
-</module>
\ No newline at end of file
+</module>
diff --git a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
index 5423da4..22b22d3 100644
--- a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
+++ b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
@@ -19,11 +19,13 @@
 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.util.collect.HashMap;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -31,11 +33,27 @@
  */
 public class ModelUtils {
 
+  static final Map<Class<?>, Class<?>> AUTOBOX_MAP;
+
   static final Set<String> VALUE_TYPES = Collections.unmodifiableSet(new HashSet<String>(
       Arrays.asList(Boolean.class.getName(), Character.class.getName(),
           Class.class.getName(), Date.class.getName(), Enum.class.getName(),
           Number.class.getName(), String.class.getName(), Void.class.getName())));
 
+  static {
+    Map<Class<?>, Class<?>> autoBoxMap = new HashMap<Class<?>, Class<?>>();
+    autoBoxMap.put(byte.class, Byte.class);
+    autoBoxMap.put(char.class, Character.class);
+    autoBoxMap.put(double.class, Double.class);
+    autoBoxMap.put(float.class, Float.class);
+    autoBoxMap.put(int.class, Integer.class);
+    autoBoxMap.put(long.class, Long.class);
+    autoBoxMap.put(short.class, Short.class);
+    autoBoxMap.put(void.class, Void.class);
+    AUTOBOX_MAP = Collections.unmodifiableMap(autoBoxMap);
+  }
+
+  
   public static JClassType[] findParameterizationOf(JClassType intfType,
       JClassType subType) {
     assert intfType.isAssignableFrom(subType) : subType.getParameterizedQualifiedSourceName()
@@ -70,6 +88,11 @@
     return false;
   }
 
+  public static Class<?> maybeAutobox(Class<?> domainType) {
+    Class<?> autoBoxType = AUTOBOX_MAP.get(domainType);
+    return autoBoxType == null ? domainType : autoBoxType;
+  }
+
   private ModelUtils() {
   }
 }
diff --git a/user/src/com/google/gwt/editor/client/ui/ValueBoxEditorDecorator.java b/user/src/com/google/gwt/editor/ui/client/ValueBoxEditorDecorator.java
similarity index 95%
rename from user/src/com/google/gwt/editor/client/ui/ValueBoxEditorDecorator.java
rename to user/src/com/google/gwt/editor/ui/client/ValueBoxEditorDecorator.java
index 9132016..eb8551e 100644
--- a/user/src/com/google/gwt/editor/client/ui/ValueBoxEditorDecorator.java
+++ b/user/src/com/google/gwt/editor/ui/client/ValueBoxEditorDecorator.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.editor.client.ui;
+package com.google.gwt.editor.ui.client;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.DivElement;
@@ -21,7 +21,7 @@
 import com.google.gwt.editor.client.EditorError;
 import com.google.gwt.editor.client.HasEditorErrors;
 import com.google.gwt.editor.client.IsEditor;
-import com.google.gwt.editor.client.adapters.ValueBoxEditor;
+import com.google.gwt.editor.ui.client.adapters.ValueBoxEditor;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiChild;
 import com.google.gwt.uibinder.client.UiConstructor;
@@ -103,7 +103,7 @@
   /**
    * The default implementation will display, but not consume, received errors
    * whose {@link EditorError#getEditor() getEditor()} method returns the Editor
-   * passed into {@link #setEditor()}.
+   * passed into {@link #setEditor}.
    */
   public void showErrors(List<EditorError> errors) {
     StringBuilder sb = new StringBuilder();
diff --git a/user/src/com/google/gwt/editor/client/ui/ValueBoxEditorDecorator.ui.xml b/user/src/com/google/gwt/editor/ui/client/ValueBoxEditorDecorator.ui.xml
similarity index 100%
rename from user/src/com/google/gwt/editor/client/ui/ValueBoxEditorDecorator.ui.xml
rename to user/src/com/google/gwt/editor/ui/client/ValueBoxEditorDecorator.ui.xml
diff --git a/user/src/com/google/gwt/editor/client/adapters/HasTextEditor.java b/user/src/com/google/gwt/editor/ui/client/adapters/HasTextEditor.java
similarity index 95%
rename from user/src/com/google/gwt/editor/client/adapters/HasTextEditor.java
rename to user/src/com/google/gwt/editor/ui/client/adapters/HasTextEditor.java
index 2c75d88..00f3fe4 100644
--- a/user/src/com/google/gwt/editor/client/adapters/HasTextEditor.java
+++ b/user/src/com/google/gwt/editor/ui/client/adapters/HasTextEditor.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.editor.client.adapters;
+package com.google.gwt.editor.ui.client.adapters;
 
 import com.google.gwt.editor.client.LeafValueEditor;
 import com.google.gwt.user.client.ui.HasText;
diff --git a/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java b/user/src/com/google/gwt/editor/ui/client/adapters/ValueBoxEditor.java
similarity index 94%
rename from user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java
rename to user/src/com/google/gwt/editor/ui/client/adapters/ValueBoxEditor.java
index 0433197..9dc6956 100644
--- a/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java
+++ b/user/src/com/google/gwt/editor/ui/client/adapters/ValueBoxEditor.java
@@ -13,10 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.editor.client.adapters;
+package com.google.gwt.editor.ui.client.adapters;
 
 import com.google.gwt.editor.client.EditorDelegate;
 import com.google.gwt.editor.client.HasEditorDelegate;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
 import com.google.gwt.user.client.ui.ValueBoxBase;
 
 import java.text.ParseException;
diff --git a/user/src/com/google/gwt/place/Place.gwt.xml b/user/src/com/google/gwt/place/Place.gwt.xml
new file mode 100644
index 0000000..56fff20
--- /dev/null
+++ b/user/src/com/google/gwt/place/Place.gwt.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
+<module>
+  <inherits name='com.google.gwt.user.User'/>
+
+  <source path="shared"/>
+  <source path="impl"/>
+  <generate-with class="com.google.gwt.place.rebind.PlaceHistoryMapperGenerator">
+    <when-type-assignable class="com.google.gwt.place.shared.PlaceHistoryMapper"/>
+  </generate-with>
+</module>
diff --git a/user/src/com/google/gwt/app/place/impl/AbstractPlaceHistoryMapper.java b/user/src/com/google/gwt/place/impl/AbstractPlaceHistoryMapper.java
similarity index 92%
rename from user/src/com/google/gwt/app/place/impl/AbstractPlaceHistoryMapper.java
rename to user/src/com/google/gwt/place/impl/AbstractPlaceHistoryMapper.java
index 28e261f..1fb4ae2 100644
--- a/user/src/com/google/gwt/app/place/impl/AbstractPlaceHistoryMapper.java
+++ b/user/src/com/google/gwt/place/impl/AbstractPlaceHistoryMapper.java
@@ -13,11 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.impl;
+package com.google.gwt.place.impl;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;
-import com.google.gwt.app.place.PlaceTokenizer;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
+import com.google.gwt.place.shared.PlaceTokenizer;
 
 /**
  * Abstract implementation of {@link PlaceHistoryMapper}.
diff --git a/user/src/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparator.java b/user/src/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparator.java
similarity index 96%
rename from user/src/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparator.java
rename to user/src/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparator.java
index 477de65..2a993cd 100644
--- a/user/src/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparator.java
+++ b/user/src/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparator.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
 import com.google.gwt.core.ext.typeinfo.JClassType;
 
diff --git a/user/src/com/google/gwt/app/rebind/PlaceHistoryGeneratorContext.java b/user/src/com/google/gwt/place/rebind/PlaceHistoryGeneratorContext.java
similarity index 97%
rename from user/src/com/google/gwt/app/rebind/PlaceHistoryGeneratorContext.java
rename to user/src/com/google/gwt/place/rebind/PlaceHistoryGeneratorContext.java
index 62cdd00..9fa62ac 100644
--- a/user/src/com/google/gwt/app/rebind/PlaceHistoryGeneratorContext.java
+++ b/user/src/com/google/gwt/place/rebind/PlaceHistoryGeneratorContext.java
@@ -13,12 +13,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
-import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.Prefix;
-import com.google.gwt.app.place.WithTokenizers;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -26,6 +22,10 @@
 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
 import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
+import com.google.gwt.place.shared.WithTokenizers;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/user/src/com/google/gwt/app/rebind/PlaceHistoryMapperGenerator.java b/user/src/com/google/gwt/place/rebind/PlaceHistoryMapperGenerator.java
similarity index 93%
rename from user/src/com/google/gwt/app/rebind/PlaceHistoryMapperGenerator.java
rename to user/src/com/google/gwt/place/rebind/PlaceHistoryMapperGenerator.java
index 8c04432..18425b9 100644
--- a/user/src/com/google/gwt/app/rebind/PlaceHistoryMapperGenerator.java
+++ b/user/src/com/google/gwt/place/rebind/PlaceHistoryMapperGenerator.java
@@ -13,12 +13,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.impl.AbstractPlaceHistoryMapper;
-import com.google.gwt.app.place.impl.AbstractPlaceHistoryMapper.PrefixAndToken;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.ext.Generator;
 import com.google.gwt.core.ext.GeneratorContext;
@@ -26,6 +22,10 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.place.impl.AbstractPlaceHistoryMapper;
+import com.google.gwt.place.impl.AbstractPlaceHistoryMapper.PrefixAndToken;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceTokenizer;
 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
 import com.google.gwt.user.rebind.SourceWriter;
 
@@ -38,7 +38,7 @@
  * </span>
  * </p>
  * Generates implementations of
- * {@link com.google.gwt.app.place.PlaceHistoryMapper PlaceHistoryMapper}.
+ * {@link com.google.gwt.place.shared.PlaceHistoryMapper PlaceHistoryMapper}.
  */
 public class PlaceHistoryMapperGenerator extends Generator {
   private PlaceHistoryGeneratorContext context;
diff --git a/user/src/com/google/gwt/app/place/Place.java b/user/src/com/google/gwt/place/shared/Place.java
similarity index 96%
rename from user/src/com/google/gwt/app/place/Place.java
rename to user/src/com/google/gwt/place/shared/Place.java
index c8b0e2c..cd1af45 100644
--- a/user/src/com/google/gwt/app/place/Place.java
+++ b/user/src/com/google/gwt/place/shared/Place.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 /**
  * <p>
diff --git a/user/src/com/google/gwt/app/place/PlaceChangeEvent.java b/user/src/com/google/gwt/place/shared/PlaceChangeEvent.java
similarity index 94%
rename from user/src/com/google/gwt/app/place/PlaceChangeEvent.java
rename to user/src/com/google/gwt/place/shared/PlaceChangeEvent.java
index 12a0127..5a4a081 100644
--- a/user/src/com/google/gwt/app/place/PlaceChangeEvent.java
+++ b/user/src/com/google/gwt/place/shared/PlaceChangeEvent.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
@@ -30,8 +30,6 @@
 
   /**
    * Implemented by handlers of PlaceChangeEvent.
-   * 
-   * @param <P> the type of the new Place
    */
   public interface Handler extends EventHandler {
     void onPlaceChange(PlaceChangeEvent event);
diff --git a/user/src/com/google/gwt/app/place/PlaceChangeRequestEvent.java b/user/src/com/google/gwt/place/shared/PlaceChangeRequestEvent.java
similarity index 96%
rename from user/src/com/google/gwt/app/place/PlaceChangeRequestEvent.java
rename to user/src/com/google/gwt/place/shared/PlaceChangeRequestEvent.java
index d4d1830..fff23d1 100644
--- a/user/src/com/google/gwt/app/place/PlaceChangeRequestEvent.java
+++ b/user/src/com/google/gwt/place/shared/PlaceChangeRequestEvent.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
@@ -33,8 +33,6 @@
 
   /**
    * Implemented by handlers of PlaceChangeRequestEvent.
-   *
-   * @param <P> the type of the requested Place
    */
   public interface Handler extends EventHandler {
     void onPlaceChangeRequest(PlaceChangeRequestEvent event);
diff --git a/user/src/com/google/gwt/app/place/PlaceController.java b/user/src/com/google/gwt/place/shared/PlaceController.java
similarity index 98%
rename from user/src/com/google/gwt/app/place/PlaceController.java
rename to user/src/com/google/gwt/place/shared/PlaceController.java
index 0d84a07..a28a5d0 100644
--- a/user/src/com/google/gwt/app/place/PlaceController.java
+++ b/user/src/com/google/gwt/place/shared/PlaceController.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.shared.EventBus;
diff --git a/user/src/com/google/gwt/app/place/PlaceHistoryHandler.java b/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
similarity index 98%
rename from user/src/com/google/gwt/app/place/PlaceHistoryHandler.java
rename to user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
index 895d496..274fd55 100644
--- a/user/src/com/google/gwt/app/place/PlaceHistoryHandler.java
+++ b/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
diff --git a/user/src/com/google/gwt/app/place/PlaceHistoryMapper.java b/user/src/com/google/gwt/place/shared/PlaceHistoryMapper.java
similarity index 96%
rename from user/src/com/google/gwt/app/place/PlaceHistoryMapper.java
rename to user/src/com/google/gwt/place/shared/PlaceHistoryMapper.java
index 59a27a1..d170761 100644
--- a/user/src/com/google/gwt/app/place/PlaceHistoryMapper.java
+++ b/user/src/com/google/gwt/place/shared/PlaceHistoryMapper.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 /**
  * <p>
diff --git a/user/src/com/google/gwt/app/place/PlaceHistoryMapperWithFactory.java b/user/src/com/google/gwt/place/shared/PlaceHistoryMapperWithFactory.java
similarity index 95%
rename from user/src/com/google/gwt/app/place/PlaceHistoryMapperWithFactory.java
rename to user/src/com/google/gwt/place/shared/PlaceHistoryMapperWithFactory.java
index 22c0b02..4d0b6b7 100644
--- a/user/src/com/google/gwt/app/place/PlaceHistoryMapperWithFactory.java
+++ b/user/src/com/google/gwt/place/shared/PlaceHistoryMapperWithFactory.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 /**
  * A PlaceHistoryMapper that can get its {@link PlaceTokenizer} instances from
diff --git a/user/src/com/google/gwt/app/place/PlaceTokenizer.java b/user/src/com/google/gwt/place/shared/PlaceTokenizer.java
similarity index 95%
rename from user/src/com/google/gwt/app/place/PlaceTokenizer.java
rename to user/src/com/google/gwt/place/shared/PlaceTokenizer.java
index 2e9628b..ebc2a71 100644
--- a/user/src/com/google/gwt/app/place/PlaceTokenizer.java
+++ b/user/src/com/google/gwt/place/shared/PlaceTokenizer.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 /**
  * Implemented by objects responsible for text serialization and deserialization
diff --git a/user/src/com/google/gwt/app/place/Prefix.java b/user/src/com/google/gwt/place/shared/Prefix.java
similarity index 91%
rename from user/src/com/google/gwt/app/place/Prefix.java
rename to user/src/com/google/gwt/place/shared/Prefix.java
index ce68c3b..8f5a761 100644
--- a/user/src/com/google/gwt/app/place/Prefix.java
+++ b/user/src/com/google/gwt/place/shared/Prefix.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -24,7 +24,7 @@
  * Indicates the prefix to use when the token written by
  * {@link PlaceTokenizer#getToken(Place)} is written to
  * {@link com.google.gwt.user.client.History#newItem}.
- * {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator} looks
+ * {@code com.google.gwt.place.rebind.PlaceHistoryMapperGenerator} looks
  * for this annotation on the factory methods that return a tokenizer, and on
  * the tokenizer types themselves.
  */
diff --git a/user/src/com/google/gwt/app/place/WithTokenizers.java b/user/src/com/google/gwt/place/shared/WithTokenizers.java
similarity index 90%
rename from user/src/com/google/gwt/app/place/WithTokenizers.java
rename to user/src/com/google/gwt/place/shared/WithTokenizers.java
index d592055..d10bbd2 100644
--- a/user/src/com/google/gwt/app/place/WithTokenizers.java
+++ b/user/src/com/google/gwt/place/shared/WithTokenizers.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -23,7 +23,7 @@
 /**
  * Indicates {@link PlaceTokenizer} types used by an implementation of
  * {@link PlaceHistoryMapper} generated by
- * {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * {@code com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 @Target({ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
diff --git a/user/src/com/google/gwt/requestfactory/RequestFactory.gwt.xml b/user/src/com/google/gwt/requestfactory/RequestFactory.gwt.xml
index 0c0dfc5..9ff3aba 100644
--- a/user/src/com/google/gwt/requestfactory/RequestFactory.gwt.xml
+++ b/user/src/com/google/gwt/requestfactory/RequestFactory.gwt.xml
@@ -23,6 +23,7 @@
 
   <source path="client"/>
   <source path="shared"/>
+  <source path="ui/client"/>
   <generate-with
     class="com.google.gwt.requestfactory.rebind.RequestFactoryEditorDriverGenerator">
     <when-type-assignable
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
index 2ebce34..2dbfd976 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
@@ -26,15 +26,16 @@
 import com.google.gwt.requestfactory.shared.EntityProxyChange;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.shared.RequestContext;
+import com.google.gwt.requestfactory.shared.RequestTransport.TransportReceiver;
 import com.google.gwt.requestfactory.shared.ServerFailure;
 import com.google.gwt.requestfactory.shared.ValueCodex;
 import com.google.gwt.requestfactory.shared.Violation;
 import com.google.gwt.requestfactory.shared.WriteOperation;
-import com.google.gwt.requestfactory.shared.RequestTransport.TransportReceiver;
 import com.google.gwt.requestfactory.shared.impl.Constants;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -56,8 +57,13 @@
    * Objects are placed into this map by being passed into {@link #edit} or as
    * an invocation argument.
    */
-  private final Map<SimpleEntityProxyId<?>, EntityProxy> seenProxies = new LinkedHashMap<SimpleEntityProxyId<?>, EntityProxy>();
+  private final Map<SimpleEntityProxyId<?>, AutoBean<?>> editedProxies = new LinkedHashMap<SimpleEntityProxyId<?>, AutoBean<?>>();
   private Set<Violation> errors = new LinkedHashSet<Violation>();
+  /**
+   * A map that contains the canonical instance of an entity to return in the
+   * return graph, since this is built from scratch.
+   */
+  private final Map<SimpleEntityProxyId<?>, AutoBean<?>> returnedProxies = new HashMap<SimpleEntityProxyId<?>, AutoBean<?>>();
 
   protected AbstractRequestContext(AbstractRequestFactory factory) {
     this.requestFactory = factory;
@@ -71,7 +77,7 @@
 
     AutoBean<T> created = requestFactory.createEntityProxy(clazz,
         requestFactory.allocateId(clazz));
-    return makeEdited(created);
+    return takeOwnership(created);
   }
 
   public <T extends EntityProxy> T edit(T object) {
@@ -80,25 +86,21 @@
     checkLocked();
 
     @SuppressWarnings("unchecked")
-    T toReturn = (T) seenProxies.get(object.stableId());
-    if (toReturn != null) {
+    AutoBean<T> previouslySeen = (AutoBean<T>) editedProxies.get(object.stableId());
+    if (previouslySeen != null && !previouslySeen.isFrozen()) {
       /*
        * If we've seen the object before, it might be because it was passed in
        * as a method argument. This does not guarantee its mutability, so check
        * that here before returning the cached object.
        */
-      AutoBean<T> previouslySeen = AutoBeanUtils.getAutoBean(toReturn);
-      if (!previouslySeen.isFrozen()) {
-        return toReturn;
-      }
+      return previouslySeen.as();
     }
 
     // Create editable copies
     AutoBean<T> parent = bean;
     bean = cloneBeanAndCollections(bean);
-    toReturn = makeEdited(bean);
     bean.setTag(PARENT_OBJECT, parent);
-    return toReturn;
+    return takeOwnership(bean);
   }
 
   /**
@@ -146,13 +148,12 @@
      * simple flag-check because of the possibility of "unmaking" a change, per
      * the JavaDoc.
      */
-    for (EntityProxy edited : seenProxies.values()) {
-      AutoBean<EntityProxy> bean = AutoBeanUtils.getAutoBean(edited);
+    for (AutoBean<?> bean : editedProxies.values()) {
       AutoBean<?> previous = bean.getTag(PARENT_OBJECT);
       if (previous == null) {
         // Compare to empty object
-        previous = getRequestFactory().getAutoBeanFactory().create(
-            edited.stableId().getProxyClass());
+        Class<?> proxyClass = ((EntityProxy) bean.as()).stableId().getProxyClass();
+        previous = getRequestFactory().getAutoBeanFactory().create(proxyClass);
       }
       if (!AutoBeanUtils.diff(previous, bean).isEmpty()) {
         return true;
@@ -182,7 +183,7 @@
    */
   protected void addInvocation(AbstractRequest<?> request) {
     if (invocations.size() > 0) {
-      // TODO(bobv): Upgrade wire protocal and server to handle chains
+      // TODO(bobv): Upgrade wire protocol and server to handle chains
       throw new IllegalStateException("Method chaining not implemented");
     }
     invocations.add(request);
@@ -192,38 +193,35 @@
   }
 
   /**
-   * Called by generated subclasses when decoding a request.
+   * Creates or retrieves a new canonical AutoBean to represent the given id in
+   * the returned payload.
    */
-  EntityProxy getSeenEntityProxy(SimpleEntityProxyId<?> id) {
-    return seenProxies.get(id);
+  <Q extends EntityProxy> AutoBean<Q> getProxyForReturnPayloadGraph(
+      SimpleEntityProxyId<Q> id) {
+    assert !id.isEphemeral();
+
+    @SuppressWarnings("unchecked")
+    AutoBean<Q> bean = (AutoBean<Q>) returnedProxies.get(id);
+    if (bean == null) {
+      Class<Q> proxyClass = id.getProxyClass();
+      bean = requestFactory.createEntityProxy(proxyClass, id);
+      returnedProxies.put(id, bean);
+    }
+
+    return bean;
   }
 
   /**
-   * Apply the deltas in a ReturnRecord to an EntityProxy.
+   * Create a new EntityProxy from a snapshot in the return payload.
    * 
-   * @param id the EntityProxyId of the object being mutated
+   * @param id the EntityProxyId of the object
    * @param returnRecord the JSON map containing property/value pairs
    * @param operations the WriteOperation eventns to broadcast over the EventBus
    */
   <Q extends EntityProxy> Q processReturnRecord(SimpleEntityProxyId<Q> id,
       final ReturnRecord returnRecord, WriteOperation... operations) {
-    @SuppressWarnings("unchecked")
-    Q proxy = (Q) seenProxies.get(id);
-    AutoBean<Q> toMutate;
 
-    if (proxy == null) {
-      // The server is sending us an object that hasn't been seen before
-      assert !id.isEphemeral();
-      Class<Q> proxyClass = id.getProxyClass();
-      toMutate = requestFactory.createEntityProxy(proxyClass, id);
-      makeEdited(toMutate);
-    } else {
-      // Create a new copy of the object
-      AutoBean<Q> original = AutoBeanUtils.getAutoBean(proxy);
-      toMutate = cloneBeanAndCollections(original);
-    }
-
-    proxy = toMutate.as();
+    AutoBean<Q> toMutate = getProxyForReturnPayloadGraph(id);
 
     // Apply updates
     toMutate.accept(new AutoBeanVisitor() {
@@ -266,6 +264,7 @@
 
     // Finished applying updates, freeze the bean
     makeImmutable(toMutate);
+    Q proxy = toMutate.as();
 
     /*
      * Notify subscribers if the object differs from when it first came into the
@@ -394,8 +393,9 @@
             if (errors.isEmpty()) {
               receiver.onSuccess(null);
               // After success, shut down the context
-              seenProxies.clear();
+              editedProxies.clear();
               invocations.clear();
+              returnedProxies.clear();
             } else {
               receiver.onViolation(errors);
             }
@@ -411,24 +411,12 @@
    * Set the frozen status of all EntityProxies owned by this context.
    */
   private void freezeEntities(boolean frozen) {
-    for (EntityProxy proxy : seenProxies.values()) {
-      AutoBean<?> bean = AutoBeanUtils.getAutoBean(proxy);
+    for (AutoBean<?> bean : editedProxies.values()) {
       bean.setFrozen(frozen);
     }
   }
 
   /**
-   * Make the EnityProxy bean edited and owned by this RequestContext.
-   */
-  private <T extends EntityProxy> T makeEdited(AutoBean<T> bean) {
-    T toReturn = bean.as();
-    seenProxies.put(EntityProxyCategory.stableId(bean), toReturn);
-    bean.setTag(EntityProxyCategory.REQUEST_CONTEXT,
-        AbstractRequestContext.this);
-    return toReturn;
-  }
-
-  /**
    * Make an EntityProxy immutable.
    */
   private void makeImmutable(final AutoBean<? extends EntityProxy> toMutate) {
@@ -456,17 +444,16 @@
     RequestContentData data = new RequestContentData();
 
     // Compute deltas for each entity seen by the context
-    for (EntityProxy proxy : seenProxies.values()) {
+    for (AutoBean<?> currentView : editedProxies.values()) {
       boolean isPersist = false;
       @SuppressWarnings("unchecked")
-      SimpleEntityProxyId<EntityProxy> stableId = (SimpleEntityProxyId<EntityProxy>) proxy.stableId();
+      SimpleEntityProxyId<EntityProxy> stableId = EntityProxyCategory.stableId((AutoBean<EntityProxy>) currentView);
 
       // Encoded string representations of the properties
       Map<String, String> encoded = new LinkedHashMap<String, String>();
 
       {
         // Find the object to compare against
-        AutoBean<?> currentView = AutoBeanUtils.getAutoBean(proxy);
         AutoBean<?> parent = currentView.getTag(PARENT_OBJECT);
         if (parent == null) {
           // Newly-created object, use a blank object to compare against
@@ -546,4 +533,14 @@
       edit((EntityProxy) arg);
     }
   }
+
+  /**
+   * Make the EnityProxy bean edited and owned by this RequestContext.
+   */
+  private <T extends EntityProxy> T takeOwnership(AutoBean<T> bean) {
+    editedProxies.put(EntityProxyCategory.stableId(bean), bean);
+    bean.setTag(EntityProxyCategory.REQUEST_CONTEXT,
+        AbstractRequestContext.this);
+    return bean.as();
+  }
 }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java b/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java
deleted file mode 100644
index dcd532a..0000000
--- a/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java
+++ /dev/null
@@ -1,65 +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.requestfactory.client.impl;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-import java.util.Map;
-
-/**
- * <p>
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * </p>
- * A convenience class to convert a Map<String, String> to a JSON string on the
- * client side.
- */
-public class ClientRequestHelper {
-
-  private static class MyJSO extends JavaScriptObject {
-    static native MyJSO create() /*-{
-      return {};
-    }-*/;
-
-    @SuppressWarnings("unused")
-    protected MyJSO() {
-    }
-
-    private native void put(String key, String value)/*-{
-      // TODO(jgw): Find a better way to do this. Occasionally a js-wrapped
-      // string ends up in 'value', which breaks the json2.js implementation
-      // of JSON.stringify().
-      this[key] = (value == null) ? null : String(value);
-    }-*/;
-
-    private native String toJsonString()/*-{
-      var gwt = this.__gwt_ObjectId;
-      delete this.__gwt_ObjectId;
-      var rtn = $wnd.JSON.stringify(this);
-      this.__gwt_ObjectId = gwt;
-      return rtn;
-    }-*/;
-  }
-
-  public static String getRequestString(Map<String, String> requestData) {
-    MyJSO request = MyJSO.create();
-    for (String key : requestData.keySet()) {
-      request.put(key, requestData.get(key));
-    }
-    return request.toJsonString();
-  }
-}
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java b/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
index e809945..64e0a1f 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
@@ -79,7 +79,8 @@
     if (requestContext.getRequestFactory().getTypeToken(type) != null) {
       EntityProxyId<?> id = requestContext.getRequestFactory().getProxyId(
           (String) jso);
-      return requestContext.getSeenEntityProxy((SimpleEntityProxyId<?>) id);
+      return requestContext.getProxyForReturnPayloadGraph(
+          (SimpleEntityProxyId<?>) id).as();
     }
 
     // Fall back to values
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/messages/RequestContentData.java b/user/src/com/google/gwt/requestfactory/client/impl/messages/RequestContentData.java
index 5a945eb..f955bf0 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/messages/RequestContentData.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/messages/RequestContentData.java
@@ -16,7 +16,6 @@
 package com.google.gwt.requestfactory.client.impl.messages;
 
 import com.google.gwt.core.client.JsonUtils;
-import com.google.gwt.requestfactory.client.impl.ClientRequestHelper;
 import com.google.gwt.requestfactory.shared.WriteOperation;
 
 import java.util.EnumMap;
@@ -33,6 +32,10 @@
    */
   public static String flattenKeysToExpressions(
       Map<String, String> keysToExpressions) {
+    if (keysToExpressions.isEmpty()) {
+      return "{}";
+    }
+
     StringBuilder flattenedProperties = new StringBuilder();
     for (Map.Entry<String, String> entry : keysToExpressions.entrySet()) {
       flattenedProperties.append(",").append(
@@ -89,7 +92,7 @@
     Map<String, String> toReturn = new LinkedHashMap<String, String>();
     addToReturn(toReturn, WriteOperation.PERSIST);
     addToReturn(toReturn, WriteOperation.UPDATE);
-    return ClientRequestHelper.getRequestString(toReturn);
+    return flattenKeysToExpressions(toReturn);
   }
 
   /**
diff --git a/user/src/com/google/gwt/requestfactory/client/testing/MockRequestFactoryEditorDriver.java b/user/src/com/google/gwt/requestfactory/client/testing/MockRequestFactoryEditorDriver.java
index 1f57378..66e4675 100644
--- a/user/src/com/google/gwt/requestfactory/client/testing/MockRequestFactoryEditorDriver.java
+++ b/user/src/com/google/gwt/requestfactory/client/testing/MockRequestFactoryEditorDriver.java
@@ -61,7 +61,6 @@
   /**
    * Returns <code>null</code> or the last value recorded.
    */
-  @SuppressWarnings("unchecked")
   public RequestContext flush() {
     return saveRequest;
   }
diff --git a/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java b/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
index 9576ffd..da5607f 100644
--- a/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
+++ b/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
@@ -20,6 +20,7 @@
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JMethod;
 import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.editor.rebind.model.ModelUtils;
@@ -32,6 +33,8 @@
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.requestfactory.shared.Service;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -54,6 +57,10 @@
         instanceRequestInterface.getSimpleSourceName());
   }
 
+  static String poisonedMessage() {
+    return "Unable to create RequestFactoryModel model due to previous errors";
+  }
+
   private final TreeLogger logger;
   private final JClassType collectionInterface;
   private final List<ContextMethod> contextMethods = new ArrayList<ContextMethod>();
@@ -118,10 +125,10 @@
     }
 
     if (poisoned) {
-      die("Unable to complete due to previous errors");
+      die(poisonedMessage());
     }
   }
-
+  
   public Collection<EntityProxyModel> getAllProxyModels() {
     return Collections.unmodifiableCollection(peers.values());
   }
@@ -150,14 +157,15 @@
    * Examine a RequestContext subtype to populate a ContextMethod.
    */
   private void buildContextMethod(ContextMethod.Builder contextBuilder,
-      JClassType contextType) {
+      JClassType contextType) throws UnableToCompleteException {
     Service serviceAnnotation = contextType.getAnnotation(Service.class);
     if (serviceAnnotation == null) {
       poison("RequestContext subtype %s is missing a @%s annotation",
           contextType.getQualifiedSourceName(), Service.class.getSimpleName());
       return;
     }
-    contextBuilder.setServiceClass(serviceAnnotation.value());
+      Class<?> serviceClass = serviceAnnotation.value();
+      contextBuilder.setServiceClass(serviceClass);
 
     List<RequestMethod> requestMethods = new ArrayList<RequestMethod>();
     for (JMethod method : contextType.getInheritableMethods()) {
@@ -169,7 +177,7 @@
       RequestMethod.Builder methodBuilder = new RequestMethod.Builder();
       methodBuilder.setDeclarationMethod(method);
 
-      if (!validateContextMethodAndSetDataType(methodBuilder, method)) {
+      if (!validateContextMethodAndSetDataType(methodBuilder, method, serviceClass)) {
         continue;
       }
 
@@ -184,7 +192,22 @@
     throw new UnableToCompleteException();
   }
 
-  private EntityProxyModel getEntityProxyType(JClassType entityProxyType) {
+  /**
+   * Return a list of public methods that match the given methodName.
+   */
+  private List<Method> findMethods(Class<?> domainType, String methodName) {
+    List<Method> toReturn = new ArrayList<Method>();
+    for (Method method : domainType.getMethods()) {
+      if (methodName.equals(method.getName())
+          && (method.getModifiers() & Modifier.PUBLIC) != 0) {
+        toReturn.add(method);
+      }
+    }
+    return toReturn;
+  }
+
+  private EntityProxyModel getEntityProxyType(JClassType entityProxyType)
+      throws UnableToCompleteException {
     EntityProxyModel toReturn = peers.get(entityProxyType);
     if (toReturn == null) {
       EntityProxyModel.Builder inProgress = peerBuilders.get(entityProxyType);
@@ -204,8 +227,12 @@
         poison("The %s type does not have a @%s annotation",
             entityProxyType.getQualifiedSourceName(),
             ProxyFor.class.getSimpleName());
+        // early exit, because further processing causes NPEs in numerous spots
+        die(poisonedMessage());
       } else {
-        builder.setProxyFor(proxyFor.value());
+        Class<?> domainType = proxyFor.value();
+        builder.setProxyFor(domainType);
+        validateDomainType(domainType);
       }
 
       // Look at the methods declared on the EntityProxy
@@ -237,7 +264,10 @@
           continue;
         }
         validateTransportableType(methodBuilder, transportedType, false);
-        requestMethods.add(methodBuilder.build());
+        RequestMethod requestMethod = methodBuilder.build();
+        if (validateDomainBeanMethod(requestMethod, builder)) {
+          requestMethods.add(requestMethod);
+        }
       }
       builder.setRequestMethods(requestMethods);
 
@@ -248,6 +278,20 @@
     return toReturn;
   }
 
+  private boolean isStatic(Method domainMethod) {
+    return (domainMethod.getModifiers() & Modifier.STATIC) != 0;
+  }
+
+  private String methodLocation(Method domainMethod) {
+    return domainMethod.getDeclaringClass().getName() + "."
+        + domainMethod.getName();
+  }
+
+  private String methodLocation(JMethod proxyMethod) {
+    return proxyMethod.getEnclosingType().getName() + "."
+        + proxyMethod.getName();
+  }
+
   private void poison(String message, Object... args) {
     logger.log(TreeLogger.ERROR, String.format(message, args));
     poisoned = true;
@@ -257,7 +301,8 @@
    * Examine a RequestContext method to see if it returns a transportable type.
    */
   private boolean validateContextMethodAndSetDataType(
-      RequestMethod.Builder methodBuilder, JMethod method) {
+          RequestMethod.Builder methodBuilder, JMethod method, Class<?> serviceClass)
+      throws UnableToCompleteException {
     JClassType requestReturnType = method.getReturnType().isInterface();
     JClassType invocationReturnType;
     if (requestReturnType == null) {
@@ -267,14 +312,44 @@
       return false;
     }
 
+    /*
+     * TODO: bad assumption
+     * Implicit assumption is that the Service and ProxyFor
+     * classes are the same. This is because an instance method should
+     * technically be looked up on the class that is the instance parameter,
+     * and not on the serviceClass, which consists of static service methods.
+     * Can't be fixed until it is fixed in JsonRequestProcessor.
+     */
+    Method domainMethod = validateExistsAndNotOverriden(method, serviceClass,
+        false);
+    if (domainMethod == null) {
+      return false;
+    }
+
+
     if (instanceRequestInterface.isAssignableFrom(requestReturnType)) {
+      if (isStatic(domainMethod)) {
+        poison("Method %s.%s is an instance method, "
+            + "while the corresponding method on %s is static",
+            method.getEnclosingType().getName(),
+            method.getName(),
+            serviceClass.getName());
+        return false;
+      }
       // Instance method invocation
       JClassType[] params = ModelUtils.findParameterizationOf(
           instanceRequestInterface, requestReturnType);
       methodBuilder.setInstanceType(getEntityProxyType(params[0]));
       invocationReturnType = params[1];
-
     } else if (requestInterface.isAssignableFrom(requestReturnType)) {
+      if (!isStatic(domainMethod)) {
+        poison("Method %s.%s is a static method, "
+            + "while the corresponding method on %s is not",
+            method.getEnclosingType().getName(),
+            method.getName(),
+            serviceClass.getName());
+        return false;
+      }
       // Static method invocation
       JClassType[] params = ModelUtils.findParameterizationOf(requestInterface,
           requestReturnType);
@@ -289,21 +364,168 @@
 
     // Validate the parameters
     boolean paramsOk = true;
-    for (JParameter param : method.getParameters()) {
+    JParameter[] params = method.getParameters();
+    Class<?>[] domainParams = domainMethod.getParameterTypes();
+    if (params.length != domainParams.length) {
+      poison("Method %s.%s parameters do not match same method on %s",
+          method.getEnclosingType().getName(),
+          method.getName(),
+          serviceClass.getName());
+    }
+    for (int i = 0; i < params.length; ++i) {
+      JParameter param = params[i];
+      Class<?> domainParam = domainParams[i];
       paramsOk = validateTransportableType(new RequestMethod.Builder(),
           param.getType(), false)
           && paramsOk;
+      paramsOk = validateProxyAndDomainTypeEquals(param.getType(), domainParam, i,
+          methodLocation(method), methodLocation(domainMethod))
+          && paramsOk;
     }
 
     return validateTransportableType(methodBuilder, invocationReturnType, true)
+        && validateProxyAndDomainTypeEquals(invocationReturnType,
+        domainMethod.getReturnType(), -1, methodLocation(method),
+        methodLocation(domainMethod))
         && paramsOk;
   }
 
   /**
+   * Examine a domain method to see if it matches the proxy method.
+   */
+  private boolean validateDomainBeanMethod(RequestMethod requestMethod,
+      EntityProxyModel.Builder entityBuilder) throws UnableToCompleteException {
+    JMethod proxyMethod = requestMethod.getDeclarationMethod();
+    // check if method exists on domain object
+    Class<?> domainType = entityBuilder.peek().getProxyFor();
+    Method domainMethod = validateExistsAndNotOverriden(proxyMethod, domainType,
+        true);
+    if (domainMethod == null) {
+      return false;
+    }
+
+    boolean isGetter = proxyMethod.getName().startsWith("get");
+    if (isGetter) {
+      // compare return type of domain to proxy return type
+      String returnTypeName = domainMethod.getReturnType().getName();
+      // isEntityType() returns true for collections, but we want the Collection
+      String propertyTypeName =
+          requestMethod.isCollectionType() || requestMethod.isValueType() ?
+              requestMethod.getDataType().getQualifiedBinaryName() :
+              requestMethod.getEntityType().getProxyFor().getName();
+      if (!returnTypeName.equals(propertyTypeName)) {
+                  poison("Method %s.%s return type %s does not match return type %s "
+              + " of method %s.%s", domainType.getName(),
+              domainMethod.getName(), returnTypeName,
+              propertyTypeName,
+              proxyMethod.getEnclosingType().getName(), proxyMethod.getName());
+        return false;
+      }
+    }
+    JParameter[] proxyParams = proxyMethod.getParameters();
+    Class<?>[] domainParams = domainMethod.getParameterTypes();
+    if (proxyParams.length != domainParams.length) {
+       poison("Method %s.%s parameter mismatch with %s.%s",
+           proxyMethod.getEnclosingType().getName(),
+           proxyMethod.getName(),
+           domainType.getName(),
+           domainMethod.getName());
+      return false;
+    }
+    for (int i = 0; i < proxyParams.length; i++) {
+      JType proxyParam = proxyParams[i].getType();
+      Class<?> domainParam = domainParams[i];
+      if (!validateProxyAndDomainTypeEquals(proxyParam, domainParam, i,
+          methodLocation(proxyMethod), methodLocation(domainMethod))) {
+        poison("Parameter %d of %s.%s doesn't match method %s.%s",
+            i, proxyMethod.getEnclosingType().getName(),
+            proxyMethod.getName(),
+            domainType.getName(),
+            domainMethod.getName());
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Examine a domain type and see if it includes a getId() method.
+   */
+  private boolean validateDomainType(Class<?> domainType) {
+    try {
+        domainType.getMethod("getId");
+    } catch (NoSuchMethodException e) {
+        poison("The class %s is missing method getId()", domainType.getName());
+        return false;
+    }
+    try {
+        domainType.getMethod("getVersion");
+    } catch (NoSuchMethodException e) {
+        poison("The class %s is missing method getVersion()", domainType.getName());
+        return false;
+    }
+    return true;
+  }
+
+  private Method validateExistsAndNotOverriden(JMethod clientMethod,
+      Class<?> serverType, boolean isGetterOrSetter) {
+    List<Method> domainMethods = findMethods(serverType, clientMethod.getName());
+    if (domainMethods.size() == 0) {
+      poison("Method %s.%s has no corresponding public method on %s",
+          clientMethod.getEnclosingType().getQualifiedBinaryName(),
+          clientMethod.getName(), serverType.getName());
+      return null;
+    }
+    if (domainMethods.size() > 1) {
+      poison("Method %s.%s is overloaded on %s",
+          clientMethod.getEnclosingType().getQualifiedBinaryName(),
+          clientMethod.getName(), serverType.getName());
+      return null;
+    }
+    Method domainMethod = domainMethods.get(0);
+    if (isGetterOrSetter && isStatic(domainMethod)) {
+      poison("Method %s.%s is declared static", serverType.getName(),
+          domainMethod.getName());
+      return null;
+    }
+    return domainMethod;
+  }
+
+  /**
+   * Compare type from Proxy and Domain.
+   */
+  private boolean validateProxyAndDomainTypeEquals(JType proxyType,
+      Class<?> domainType, int paramNumber, String clientMethod,
+      String serverMethod) throws UnableToCompleteException {
+    boolean matchOk = false;
+    if (ModelUtils.isValueType(oracle, proxyType)
+        || collectionInterface.isAssignableFrom(proxyType.isClassOrInterface())) {
+      // allow int to match int or Integer
+      matchOk = proxyType.getQualifiedSourceName().equals(
+          ModelUtils.maybeAutobox(domainType).getName())
+        || proxyType.getQualifiedSourceName().equals(domainType.getName());
+    } else {
+      matchOk =  getEntityProxyType(
+          proxyType.isClassOrInterface()).getProxyFor().equals(domainType);
+    }
+    if (!matchOk) {
+      if (paramNumber < 0) {
+        poison("Return type of method %s does not match method %s", clientMethod,
+            serverMethod);
+      } else {
+         poison("Parameter %d of method %s does not match method %s",
+          paramNumber, clientMethod, serverMethod);
+      }
+    }
+    return matchOk;
+  }
+
+  /**
    * Examines a type to see if it can be transported.
    */
   private boolean validateTransportableType(
-      RequestMethod.Builder methodBuilder, JType type, boolean requireObject) {
+      RequestMethod.Builder methodBuilder, JType type, boolean requireObject)
+      throws UnableToCompleteException {
     JClassType transportedClass = type.isClassOrInterface();
     if (transportedClass == null) {
       if (requireObject) {
@@ -324,9 +546,14 @@
       methodBuilder.setEntityType(getEntityProxyType(transportedClass));
     } else if (collectionInterface.isAssignableFrom(transportedClass)) {
       // Only allow certain collections for now
-      if (listInterface.equals(transportedClass.isParameterized().getBaseType())) {
+      JParameterizedType parameterized = transportedClass.isParameterized();
+      if (parameterized == null) {
+        poison("Requests that return collections of List or Set must be parameterized");
+        return false;
+      }
+      if (listInterface.equals(parameterized.getBaseType())) {
         methodBuilder.setCollectionType(CollectionType.LIST);
-      } else if (setInterface.equals(transportedClass.isParameterized().getBaseType())) {
+      } else if (setInterface.equals(parameterized.getBaseType())) {
         methodBuilder.setCollectionType(CollectionType.SET);
       } else {
         poison("Requests that return collections may be declared with"
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
index 81ef9aa..8b63c1b 100644
--- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -62,13 +62,22 @@
 public class JsonRequestProcessor implements RequestProcessor<String> {
 
   // TODO should we consume String, InputStream, or JSONObject?
-  private static class DvsData {
+  private class DvsData {
     private final JSONObject jsonObject;
     private final WriteOperation writeOperation;
+    // save version because it is deleted later.
+    private final Integer version;
 
-    DvsData(JSONObject jsonObject, WriteOperation writeOperation) {
+    DvsData(JSONObject jsonObject, WriteOperation writeOperation)
+        throws JSONException, SecurityException, IllegalAccessException,
+        InvocationTargetException, NoSuchMethodException,
+        InstantiationException {
       this.jsonObject = jsonObject;
       this.writeOperation = writeOperation;
+      this.version = (Integer) (jsonObject.has(Constants.ENCODED_VERSION_PROPERTY)
+          ? decodeParameterValue(Constants.ENTITY_VERSION_PROPERTY.getType(),
+              jsonObject.get(Constants.ENCODED_VERSION_PROPERTY).toString())
+          : null);
     }
   }
 
@@ -618,19 +627,15 @@
       Class<? extends EntityProxy> entityKeyClass,
       RequestProperty propertyContext) throws JSONException,
       NoSuchMethodException, IllegalAccessException, InvocationTargetException {
-    JSONObject jsonObject = new JSONObject();
     if (entityElement == null
         || !EntityProxy.class.isAssignableFrom(entityKeyClass)) {
       // JSONObject.NULL isn't a JSONObject
       return JSONObject.NULL;
     }
+    JSONObject jsonObject = getJsonObjectWithIdAndVersion(
+        isEntityReference(entityElement, entityKeyClass), entityElement,
+        propertyContext);
 
-    jsonObject.put(Constants.ENCODED_ID_PROPERTY, isEntityReference(
-        entityElement, entityKeyClass));
-    jsonObject.put(Constants.ENCODED_VERSION_PROPERTY,
-        encodePropertyValueFromDataStore(entityElement,
-            Constants.ENTITY_VERSION_PROPERTY,
-            Constants.ENTITY_VERSION_PROPERTY.getName(), propertyContext));
     for (Property<?> p : allProperties(entityKeyClass)) {
       if (requestedProperty(p, propertyContext)) {
         String propertyName = p.getName();
@@ -1146,7 +1151,8 @@
    * Decode deltaValueStore to populate involvedKeys and dvsDataMap.
    */
   private void decodeDVS(String content) throws SecurityException,
-      JSONException {
+      JSONException, IllegalAccessException, InvocationTargetException,
+      NoSuchMethodException, InstantiationException {
     JSONObject jsonObject = new JSONObject(content);
     for (WriteOperation writeOperation : WriteOperation.values()) {
       if (!jsonObject.has(writeOperation.name())) {
@@ -1178,26 +1184,6 @@
     }
   }
 
-  private WriteOperation detectDeleteOrUpdate(EntityKey entityKey,
-      EntityData entityData) throws IllegalArgumentException,
-      SecurityException, IllegalAccessException, InvocationTargetException,
-      NoSuchMethodException, JSONException, InstantiationException {
-    if (entityData == null || entityData.entityInstance == null) {
-      return null;
-    }
-
-    Object entityInstance = getEntityInstance(entityKey);
-    if (entityInstance == null) {
-      return WriteOperation.DELETE;
-    }
-    SerializedEntity beforeEntity = beforeDataMap.get(entityKey);
-    if (beforeEntity != null && hasChanged(beforeEntity.serializedEntity,
-        serializeEntity(entityInstance, entityKey))) {
-      return WriteOperation.UPDATE;
-    }
-    return null;
-  }
-
   private String encodeId(Object id) {
     if (id instanceof String) {
       return base64Encode((String) id);
@@ -1235,10 +1221,6 @@
     assert originalEntityKey.isFuture;
     Object entityInstance = entityData.entityInstance;
     assert entityInstance != null;
-    JSONObject returnObject = new JSONObject();
-    returnObject.put(Constants.ENCODED_FUTUREID_PROPERTY,
-        originalEntityKey.encodedId + "");
-    // violations have already been taken care of.
     Object newId = getRawPropertyValueFromDatastore(entityInstance,
         Constants.ENTITY_ID_PROPERTY);
     if (newId == null) {
@@ -1248,12 +1230,12 @@
     }
 
     newId = encodeId(newId);
-    returnObject.put(Constants.ENCODED_ID_PROPERTY, getSchemaAndId(
-        originalEntityKey.proxyType, newId));
-    returnObject.put(Constants.ENCODED_VERSION_PROPERTY,
-        encodePropertyValueFromDataStore(entityInstance,
-            Constants.ENTITY_VERSION_PROPERTY,
-            Constants.ENTITY_VERSION_PROPERTY.getName(), propertyRefs));
+    JSONObject returnObject = getJsonObjectWithIdAndVersion(
+        getSchemaAndId(originalEntityKey.proxyType, newId), entityInstance,
+        propertyRefs);
+    // violations have already been taken care of.
+    returnObject.put(Constants.ENCODED_FUTUREID_PROPERTY,
+        originalEntityKey.encodedId + "");
     return returnObject;
   }
 
@@ -1277,29 +1259,17 @@
     return idMethod;
   }
 
-  private Object getPropertyValueFromRequestCached(JSONObject recordObject,
-      Map<String, Property<?>> propertiesInProxy, String key,
-      Property<?> dtoProperty) throws JSONException, IllegalAccessException,
-      InvocationTargetException, NoSuchMethodException, InstantiationException {
-    Object propertyValue;
-    if (!recordObject.isNull(key)
-        && EntityProxy.class.isAssignableFrom(dtoProperty.getType())) {
-      // if the property type is a Proxy, we expect an encoded Key string
-      EntityKey propKey = getEntityKey(recordObject.getString(key));
-      // check to see if we've already decoded this object from JSON
-      Object cacheValue = cachedEntityLookup.get(propKey);
-      // containsKey is used here because an entity lookup can return null
-      if (cachedEntityLookup.containsKey(propKey)) {
-        propertyValue = cacheValue;
-      } else {
-        propertyValue = getPropertyValueFromRequest(recordObject, key,
-            propertiesInProxy.get(key).getType());
-      }
-    } else {
-      propertyValue = getPropertyValueFromRequest(recordObject, key,
-          propertiesInProxy.get(key).getType());
-    }
-    return propertyValue;
+  private JSONObject getJsonObjectWithIdAndVersion(String encodedId,
+      Object entityElement, RequestProperty propertyContext)
+      throws JSONException, SecurityException, NoSuchMethodException,
+      IllegalAccessException, InvocationTargetException {
+    JSONObject jsonObject = new JSONObject();
+    jsonObject.put(Constants.ENCODED_ID_PROPERTY, encodedId);
+    jsonObject.put(Constants.ENCODED_VERSION_PROPERTY,
+        encodePropertyValueFromDataStore(entityElement,
+            Constants.ENTITY_VERSION_PROPERTY,
+            Constants.ENTITY_VERSION_PROPERTY.getName(), propertyContext));
+    return jsonObject;
   }
 
   private Object getPropertyValueFromRequestCached(JSONArray recordArray,
@@ -1329,6 +1299,31 @@
     return propertyValue;
   }
 
+  private Object getPropertyValueFromRequestCached(JSONObject recordObject,
+      Map<String, Property<?>> propertiesInProxy, String key,
+      Property<?> dtoProperty) throws JSONException, IllegalAccessException,
+      InvocationTargetException, NoSuchMethodException, InstantiationException {
+    Object propertyValue;
+    if (!recordObject.isNull(key)
+        && EntityProxy.class.isAssignableFrom(dtoProperty.getType())) {
+      // if the property type is a Proxy, we expect an encoded Key string
+      EntityKey propKey = getEntityKey(recordObject.getString(key));
+      // check to see if we've already decoded this object from JSON
+      Object cacheValue = cachedEntityLookup.get(propKey);
+      // containsKey is used here because an entity lookup can return null
+      if (cachedEntityLookup.containsKey(propKey)) {
+        propertyValue = cacheValue;
+      } else {
+        propertyValue = getPropertyValueFromRequest(recordObject, key,
+            propertiesInProxy.get(key).getType());
+      }
+    } else {
+      propertyValue = getPropertyValueFromRequest(recordObject, key,
+          propertiesInProxy.get(key).getType());
+    }
+    return propertyValue;
+  }
+
   private Object getRawPropertyValueFromDatastore(Object entityElement,
       String propertyName) throws SecurityException, NoSuchMethodException,
       IllegalAccessException, InvocationTargetException {
@@ -1368,6 +1363,7 @@
       if (entityData == null) {
         continue;
       }
+      // handle CREATE
       if (entityKey.isFuture) {
         JSONObject createRecord = getCreateReturnRecord(entityKey, entityData);
         if (createRecord != null) {
@@ -1375,19 +1371,35 @@
         }
         continue;
       }
-      WriteOperation writeOperation = detectDeleteOrUpdate(entityKey,
-          entityData);
-      if (writeOperation == WriteOperation.DELETE) {
+      // handle DELETE
+      Object entityInstanceAfterOperation = getEntityInstance(entityKey);
+      if (null == entityInstanceAfterOperation) {
         JSONObject deleteRecord = new JSONObject();
-        deleteRecord.put(Constants.ENCODED_ID_PROPERTY, getSchemaAndId(
-            entityKey.proxyType, entityKey.encodedId));
+        deleteRecord.put(Constants.ENCODED_ID_PROPERTY,
+            getSchemaAndId(entityKey.proxyType, entityKey.encodedId));
         deleteArray.put(deleteRecord);
+        continue;
       }
-      if (writeOperation == WriteOperation.UPDATE) {
-        JSONObject updateRecord = new JSONObject();
-        updateRecord.put(Constants.ENCODED_ID_PROPERTY, getSchemaAndId(
-            entityKey.proxyType, entityKey.encodedId));
-        updateArray.put(updateRecord);
+      /*
+       * Send an UPDATE if the client is at a version different than that of the
+       * server or if the server version has changed after invoking the domain
+       * method.
+       */
+      boolean clientNeedsUpdating = false;
+      DvsData dvsData = dvsDataMap.get(entityKey);
+      if (dvsData != null && dvsData.version != null) {
+        Integer serverVersion = (Integer) getRawPropertyValueFromDatastore(
+            entityInstanceAfterOperation,
+            Constants.ENTITY_VERSION_PROPERTY.getName());
+        if (!dvsData.version.equals(serverVersion)) {
+          clientNeedsUpdating = true;
+        }
+      }
+      if (clientNeedsUpdating
+          || hasServerVersionChanged(entityKey, entityInstanceAfterOperation)) {
+        updateArray.put(getJsonObjectWithIdAndVersion(
+            getSchemaAndId(entityKey.proxyType, entityKey.encodedId),
+            entityInstanceAfterOperation, propertyRefs));
       }
     }
     if (createArray.length() > 0) {
@@ -1429,6 +1441,18 @@
     return violations;
   }
 
+  private boolean hasServerVersionChanged(EntityKey entityKey,
+      Object entityInstanceAfterOperation) throws IllegalArgumentException,
+      SecurityException, IllegalAccessException, InvocationTargetException,
+      NoSuchMethodException, JSONException, InstantiationException {
+    SerializedEntity beforeEntity = beforeDataMap.get(entityKey);
+    if (beforeEntity != null && hasChanged(beforeEntity.serializedEntity,
+        serializeEntity(entityInstanceAfterOperation, entityKey))) {
+      return true;
+    }
+    return false;
+  }
+
   private String isEntityReference(Object entity, Class<?> proxyPropertyType)
       throws SecurityException, NoSuchMethodException,
       IllegalArgumentException, IllegalAccessException,
diff --git a/user/src/com/google/gwt/requestfactory/client/AuthenticationFailureHandler.java b/user/src/com/google/gwt/requestfactory/ui/client/AuthenticationFailureHandler.java
similarity index 97%
rename from user/src/com/google/gwt/requestfactory/client/AuthenticationFailureHandler.java
rename to user/src/com/google/gwt/requestfactory/ui/client/AuthenticationFailureHandler.java
index 6dc5be0..beb0f41 100644
--- a/user/src/com/google/gwt/requestfactory/client/AuthenticationFailureHandler.java
+++ b/user/src/com/google/gwt/requestfactory/ui/client/AuthenticationFailureHandler.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.google.gwt.requestfactory.client;
+package com.google.gwt.requestfactory.ui.client;
 
 import com.google.gwt.http.client.Response;
 import com.google.gwt.requestfactory.shared.RequestEvent;
diff --git a/user/src/com/google/gwt/app/place/EntityProxyKeyProvider.java b/user/src/com/google/gwt/requestfactory/ui/client/EntityProxyKeyProvider.java
similarity index 71%
rename from user/src/com/google/gwt/app/place/EntityProxyKeyProvider.java
rename to user/src/com/google/gwt/requestfactory/ui/client/EntityProxyKeyProvider.java
index ac88236..669cb29 100644
--- a/user/src/com/google/gwt/app/place/EntityProxyKeyProvider.java
+++ b/user/src/com/google/gwt/requestfactory/ui/client/EntityProxyKeyProvider.java
@@ -13,13 +13,19 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.requestfactory.ui.client;
 
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.view.client.ProvidesKey;
 
 /**
- * A {@link Record}-aware key provider.
+ * An {@link EntityProxy}-aware key provider, handy for use with
+ * {@link com.google.gwt.view.client.SelectionModel} and various
+ * cell widgets.
+ * 
+ * @see com.google.gwt.user.cellview.client.CellBrowser
+ * @see com.google.gwt.user.cellview.client.CellList
+ * @see com.google.gwt.user.cellview.client.CellTable
  * 
  * @param <P> the proxy type
  */
diff --git a/user/src/com/google/gwt/requestfactory/client/LoginWidget.java b/user/src/com/google/gwt/requestfactory/ui/client/LoginWidget.java
similarity index 93%
rename from user/src/com/google/gwt/requestfactory/client/LoginWidget.java
rename to user/src/com/google/gwt/requestfactory/ui/client/LoginWidget.java
index 95f418f..f78b5e31 100644
--- a/user/src/com/google/gwt/requestfactory/client/LoginWidget.java
+++ b/user/src/com/google/gwt/requestfactory/ui/client/LoginWidget.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.google.gwt.requestfactory.client;
+package com.google.gwt.requestfactory.ui.client;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.SpanElement;
@@ -47,8 +47,7 @@
   }
   
   @UiHandler("logoutLink")
-  @SuppressWarnings("unused") 
-  void handleClick(ClickEvent e) {
+  void handleClick(@SuppressWarnings("unused") ClickEvent e) {
     if (logoutUrl != "") {
       Location.replace(logoutUrl);
     }
diff --git a/user/src/com/google/gwt/requestfactory/client/LoginWidget.ui.xml b/user/src/com/google/gwt/requestfactory/ui/client/LoginWidget.ui.xml
similarity index 100%
rename from user/src/com/google/gwt/requestfactory/client/LoginWidget.ui.xml
rename to user/src/com/google/gwt/requestfactory/ui/client/LoginWidget.ui.xml
diff --git a/user/src/com/google/gwt/app/place/ProxyRenderer.java b/user/src/com/google/gwt/requestfactory/ui/client/ProxyRenderer.java
similarity index 95%
rename from user/src/com/google/gwt/app/place/ProxyRenderer.java
rename to user/src/com/google/gwt/requestfactory/ui/client/ProxyRenderer.java
index 3b7ce42..375d839 100644
--- a/user/src/com/google/gwt/app/place/ProxyRenderer.java
+++ b/user/src/com/google/gwt/requestfactory/ui/client/ProxyRenderer.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.requestfactory.ui.client;
 
 import com.google.gwt.text.shared.AbstractRenderer;
 
diff --git a/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java b/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java
index b9e4c6e..58207fb 100644
--- a/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java
+++ b/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java
@@ -16,7 +16,6 @@
 
 package com.google.gwt.rpc.linker;
 
-import com.google.gwt.core.ext.linker.CastableTypeMap;
 import com.google.gwt.rpc.server.CastableTypeData;
 
 /**
@@ -24,14 +23,14 @@
  */
 public class CastableTypeDataImpl implements CastableTypeData {
   
-  private final CastableTypeMap castableTypeMap;
+  private final String castableTypeMapJs;
   
-  public CastableTypeDataImpl(CastableTypeMap castableTypeMap) {
-    this.castableTypeMap = castableTypeMap;
+  public CastableTypeDataImpl(String castableTypeMapJs) {
+    this.castableTypeMapJs = castableTypeMapJs;
   }
 
   public String toJs() {
-    return castableTypeMap.toJs();
+    return castableTypeMapJs;
   }
 
 }
diff --git a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
index 7f9ff78..eb3c555 100644
--- a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
+++ b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
@@ -69,10 +69,15 @@
         }
 
         for (SymbolData symbolData : result.getSymbolMap()) {
+          
+          String castableTypeMapString =
+              (symbolData.getCastableTypeMap() == null) ? null :
+                symbolData.getCastableTypeMap().toJs();
+       
           builder.add(symbolData.getSymbolName(), symbolData.getJsniIdent(),
               symbolData.getClassName(), symbolData.getMemberName(),
               symbolData.getQueryId(), 
-              new CastableTypeDataImpl(symbolData.getCastableTypeMap()));
+              new CastableTypeDataImpl(castableTypeMapString));
         }
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/user/src/com/google/gwt/text/Text.gwt.xml b/user/src/com/google/gwt/text/Text.gwt.xml
index b841ec9..babbe40 100644
--- a/user/src/com/google/gwt/text/Text.gwt.xml
+++ b/user/src/com/google/gwt/text/Text.gwt.xml
@@ -16,4 +16,5 @@
 <module>
    <inherits name="com.google.gwt.core.Core"/>
    <source path="shared"/>
+   <source path="client"/>
 </module>
diff --git a/user/src/com/google/gwt/i18n/client/DateTimeFormatRenderer.java b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
similarity index 91%
rename from user/src/com/google/gwt/i18n/client/DateTimeFormatRenderer.java
rename to user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
index b17f818..9a8699b 100644
--- a/user/src/com/google/gwt/i18n/client/DateTimeFormatRenderer.java
+++ b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
@@ -13,8 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.i18n.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
 import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
 import com.google.gwt.text.shared.AbstractRenderer;
 
@@ -28,7 +30,7 @@
   private final TimeZone timeZone;
 
   /**
-   * Create an instance using {@link PredefinedFormat#DATE_SHORT}
+   * Create an instance using {@link PredefinedFormat#DATE_SHORT}.
    */
   public DateTimeFormatRenderer() {
     this(DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT));
@@ -51,7 +53,7 @@
 
   public String render(Date object) {
     if (object == null) {
-      return toString(object);
+      return "";
     }
     return timeZone == null ? format.format(object) : format.format(object,
         timeZone);
diff --git a/user/src/com/google/gwt/app/client/DoubleParser.java b/user/src/com/google/gwt/text/client/DoubleParser.java
similarity index 77%
rename from user/src/com/google/gwt/app/client/DoubleParser.java
rename to user/src/com/google/gwt/text/client/DoubleParser.java
index b9f3e14..b3d3560 100644
--- a/user/src/com/google/gwt/app/client/DoubleParser.java
+++ b/user/src/com/google/gwt/text/client/DoubleParser.java
@@ -13,18 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.Parser;
 
 import java.text.ParseException;
 
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * Simple unlocalized parser of Double that wraps {@link Double#valueOf(String)}.
+ * A localized parser based on {@link NumberFormat#getDecimalFormat}.
  */
 public class DoubleParser implements Parser<Double> {
 
@@ -44,8 +41,12 @@
   }
 
   public Double parse(CharSequence object) throws ParseException {
+    if ("".equals(object.toString())) {
+      return null;
+    }
+
     try {
-      return Double.valueOf(object.toString());
+      return Math.rint(NumberFormat.getDecimalFormat().parse(object.toString()));
     } catch (NumberFormatException e) {
       throw new ParseException(e.getMessage(), 0);
     }
diff --git a/user/src/com/google/gwt/app/client/DoubleRenderer.java b/user/src/com/google/gwt/text/client/DoubleRenderer.java
similarity index 79%
rename from user/src/com/google/gwt/app/client/DoubleRenderer.java
rename to user/src/com/google/gwt/text/client/DoubleRenderer.java
index 17d4c58..4c53c1e 100644
--- a/user/src/com/google/gwt/app/client/DoubleRenderer.java
+++ b/user/src/com/google/gwt/text/client/DoubleRenderer.java
@@ -13,17 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.AbstractRenderer;
 import com.google.gwt.text.shared.Renderer;
 
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * A simple unlocalized renderer of Long values.
+ * A localized renderer based on {@link NumberFormat#getDecimalFormat}.
  */
 public class DoubleRenderer extends AbstractRenderer<Double> {
   private static DoubleRenderer INSTANCE;
@@ -42,6 +39,10 @@
   }
 
   public String render(Double object) {
-    return toString(object);
+    if (object == null) {
+      return "";
+    }
+    
+    return NumberFormat.getDecimalFormat().format(object);
   }
 }
diff --git a/user/src/com/google/gwt/app/client/IntegerParser.java b/user/src/com/google/gwt/text/client/IntegerParser.java
similarity index 74%
rename from user/src/com/google/gwt/app/client/IntegerParser.java
rename to user/src/com/google/gwt/text/client/IntegerParser.java
index 43751da..f959fb0 100644
--- a/user/src/com/google/gwt/app/client/IntegerParser.java
+++ b/user/src/com/google/gwt/text/client/IntegerParser.java
@@ -1,35 +1,32 @@
 /*
  * Copyright 2010 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.Parser;
 
 import java.text.ParseException;
 
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * A simple unlocalized parser based on {@link Integer#valueOf(String)}.
+ * A localized parser based on {@link NumberFormat#getDecimalFormat}.
  */
 public class IntegerParser implements Parser<Integer> {
 
   private static IntegerParser INSTANCE;
-  
+
   /**
    * @return the instance of the no-op renderer
    */
@@ -39,14 +36,18 @@
     }
     return INSTANCE;
   }
-  
+
   protected IntegerParser() {
   }
 
   public Integer parse(CharSequence object) throws ParseException {
+    if ("".equals(object.toString())) {
+      return null;
+    }
+
     try {
-      return Integer.valueOf(object.toString());
-    } catch (NumberFormatException e) { 
+      return (int) Math.rint(NumberFormat.getDecimalFormat().parse(object.toString()));
+    } catch (NumberFormatException e) {
       throw new ParseException(e.getMessage(), 0);
     }
   }
diff --git a/user/src/com/google/gwt/app/client/IntegerRenderer.java b/user/src/com/google/gwt/text/client/IntegerRenderer.java
similarity index 79%
rename from user/src/com/google/gwt/app/client/IntegerRenderer.java
rename to user/src/com/google/gwt/text/client/IntegerRenderer.java
index 036df4e..d9efe2d 100644
--- a/user/src/com/google/gwt/app/client/IntegerRenderer.java
+++ b/user/src/com/google/gwt/text/client/IntegerRenderer.java
@@ -13,17 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.AbstractRenderer;
 import com.google.gwt.text.shared.Renderer;
 
+
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * Renderer of Integer values.
+ * A localized renderer based on {@link NumberFormat#getDecimalFormat}.
  */
 public class IntegerRenderer extends AbstractRenderer<Integer> {
   private static IntegerRenderer INSTANCE;
@@ -42,6 +40,10 @@
   }
 
   public String render(Integer object) {
-    return toString(object);
+    if (null == object) {
+      return "";
+    }
+    
+    return NumberFormat.getDecimalFormat().format(object);
   }
 }
diff --git a/user/src/com/google/gwt/app/client/LongParser.java b/user/src/com/google/gwt/text/client/LongParser.java
similarity index 79%
rename from user/src/com/google/gwt/app/client/LongParser.java
rename to user/src/com/google/gwt/text/client/LongParser.java
index 49d1a87..f896ca4 100644
--- a/user/src/com/google/gwt/app/client/LongParser.java
+++ b/user/src/com/google/gwt/text/client/LongParser.java
@@ -13,18 +13,16 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.Parser;
 
 import java.text.ParseException;
 
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * A no-op renderer.
+ * A localized parser based on {@link NumberFormat#getDecimalFormat}.
  */
 public class LongParser implements Parser<Long> {
 
@@ -44,8 +42,12 @@
   }
 
   public Long parse(CharSequence object) throws ParseException {
+    if ("".equals(object.toString())) {
+      return null;
+    }
+
     try {
-      return Long.valueOf(object.toString());
+      return (long) NumberFormat.getDecimalFormat().parse(object.toString());
     } catch (NumberFormatException e) { 
       throw new ParseException(e.getMessage(), 0);
     }
diff --git a/user/src/com/google/gwt/app/client/LongRenderer.java b/user/src/com/google/gwt/text/client/LongRenderer.java
similarity index 79%
rename from user/src/com/google/gwt/app/client/LongRenderer.java
rename to user/src/com/google/gwt/text/client/LongRenderer.java
index 6e16280..0c3a92a 100644
--- a/user/src/com/google/gwt/app/client/LongRenderer.java
+++ b/user/src/com/google/gwt/text/client/LongRenderer.java
@@ -13,17 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.text.client;
 
+import com.google.gwt.i18n.client.NumberFormat;
 import com.google.gwt.text.shared.AbstractRenderer;
 import com.google.gwt.text.shared.Renderer;
 
+
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
- * Renderer of Long values.
+ * A localized renderer based on {@link NumberFormat#getDecimalFormat}.
  */
 public class LongRenderer extends AbstractRenderer<Long> {
   private static LongRenderer INSTANCE;
@@ -42,6 +40,10 @@
   }
 
   public String render(Long object) {
-    return toString(object);
+    if (object == null) {
+      return "";
+    }
+
+    return NumberFormat.getDecimalFormat().format(object);
   }
 }
diff --git a/user/src/com/google/gwt/text/shared/AbstractRenderer.java b/user/src/com/google/gwt/text/shared/AbstractRenderer.java
index 4e5b520..3c69c9e 100644
--- a/user/src/com/google/gwt/text/shared/AbstractRenderer.java
+++ b/user/src/com/google/gwt/text/shared/AbstractRenderer.java
@@ -31,8 +31,4 @@
   public void render(T object, Appendable appendable) throws IOException {
     appendable.append(render(object));
   }
-
-  protected String toString(Object obj) {
-    return obj == null ? "" : String.valueOf(obj);
-  }
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/text/shared/PassthroughParser.java b/user/src/com/google/gwt/text/shared/testing/PassthroughParser.java
similarity index 93%
rename from user/src/com/google/gwt/text/shared/PassthroughParser.java
rename to user/src/com/google/gwt/text/shared/testing/PassthroughParser.java
index 5e3ecc9..3cc6555 100644
--- a/user/src/com/google/gwt/text/shared/PassthroughParser.java
+++ b/user/src/com/google/gwt/text/shared/testing/PassthroughParser.java
@@ -13,7 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.text.shared;
+package com.google.gwt.text.shared.testing;
+
+import com.google.gwt.text.shared.Parser;
+
 
 /**
  * <span style="color:red">Experimental API: This class is still under rapid
diff --git a/user/src/com/google/gwt/text/shared/PassthroughRenderer.java b/user/src/com/google/gwt/text/shared/testing/PassthroughRenderer.java
similarity index 90%
rename from user/src/com/google/gwt/text/shared/PassthroughRenderer.java
rename to user/src/com/google/gwt/text/shared/testing/PassthroughRenderer.java
index 493540b..4967058 100644
--- a/user/src/com/google/gwt/text/shared/PassthroughRenderer.java
+++ b/user/src/com/google/gwt/text/shared/testing/PassthroughRenderer.java
@@ -13,7 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.text.shared;
+package com.google.gwt.text.shared.testing;
+
+import com.google.gwt.text.shared.AbstractRenderer;
+import com.google.gwt.text.shared.Renderer;
+
 
 /**
  * <span style="color:red">Experimental API: This class is still under rapid
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
index f352f8f..10664ca 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
@@ -69,6 +69,15 @@
  * the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
  * declaration.
  * </p>
+ *
+ * <p>
+ * <h3>Example</h3>
+ * <dl>
+ * <dt>Trivial example</dt>
+ * <dd>TODO example com.google.gwt.examples.cellview.CellBrowserExample</dd>
+ * <dt>Complex example</dt>
+ * <dd>TODO example com.google.gwt.examples.cellview.CellBrowserExample2</dd>
+ * </dl>
  */
 public class CellBrowser extends AbstractCellTree implements ProvidesResize,
     RequiresResize, HasAnimation {
@@ -181,7 +190,7 @@
 
   /**
    * A custom version of cell list used by the browser. Visible for testing.
-   * 
+   *
    * @param <T> the data type of list items
    */
   class BrowserCellList<T> extends CellList<T> {
@@ -356,7 +365,7 @@
 
   /**
    * A node in the tree.
-   * 
+   *
    * @param <C> the data type of the children of the node
    */
   class TreeNodeImpl<C> implements TreeNode {
@@ -368,7 +377,7 @@
 
     /**
      * Construct a new {@link TreeNodeImpl}.
-     * 
+     *
      * @param nodeInfo the nodeInfo for the children nodes
      * @param value the value of the node
      * @param display the display associated with the node
@@ -482,7 +491,7 @@
 
     /**
      * Check the child bounds.
-     * 
+     *
      * @param index the index of the child
      * @throws IndexOutOfBoundsException if the child is not in range
      */
@@ -505,7 +514,7 @@
 
     /**
      * Get the index of the open item.
-     * 
+     *
      * @return the index of the open item, or -1 if not found
      */
     private int getOpenIndex() {
@@ -700,7 +709,7 @@
 
   /**
    * Construct a new {@link CellBrowser}.
-   * 
+   *
    * @param <T> the type of data in the root node
    * @param viewModel the {@link TreeViewModel} that backs the tree
    * @param rootValue the hidden root value of the tree
@@ -711,7 +720,7 @@
 
   /**
    * Construct a new {@link CellBrowser} with the specified {@link Resources}.
-   * 
+   *
    * @param <T> the type of data in the root node
    * @param viewModel the {@link TreeViewModel} that backs the tree
    * @param rootValue the hidden root value of the tree
@@ -762,7 +771,7 @@
 
   /**
    * Get the default width of new columns.
-   * 
+   *
    * @return the default width in pixels
    */
   public int getDefaultColumnWidth() {
@@ -771,7 +780,7 @@
 
   /**
    * Get the minimum width of columns.
-   * 
+   *
    * @return the minimum width in pixels
    */
   public int getMinimumColumnWidth() {
@@ -808,7 +817,7 @@
 
   /**
    * Set the default width of new columns.
-   * 
+   *
    * @param width the default width in pixels
    */
   public void setDefaultColumnWidth(int width) {
@@ -825,7 +834,7 @@
 
   /**
    * Set the minimum width of columns.
-   * 
+   *
    * @param minWidth the minimum width in pixels
    */
   public void setMinimumColumnWidth(int minWidth) {
@@ -834,7 +843,7 @@
 
   /**
    * Create a pager to control the list view.
-   * 
+   *
    * @param <C> the item type in the list view
    * @param display the list view to add paging too
    * @return the pager
@@ -863,7 +872,7 @@
   /**
    * Create a new {@link TreeNodeImpl} and append it to the end of the
    * LayoutPanel.
-   * 
+   *
    * @param <C> the data type of the children
    * @param nodeInfo the info about the node
    * @param value the value of the open node
@@ -914,7 +923,7 @@
   /**
    * Create a {@link HasData} that will display items. The {@link HasData} must
    * extend {@link Widget}.
-   * 
+   *
    * @param <C> the item type in the list view
    * @param nodeInfo the node info with child data
    * @param level the level of the list
@@ -930,7 +939,7 @@
 
   /**
    * Get the HTML representation of an image.
-   * 
+   *
    * @param res the {@link ImageResource} to render as HTML
    * @return the rendered HTML
    */
@@ -944,7 +953,7 @@
 
   /**
    * Get the {@link SplitLayoutPanel} used to lay out the views.
-   * 
+   *
    * @return the {@link SplitLayoutPanel}
    */
   private SplitLayoutPanel getSplitLayoutPanel() {
@@ -953,7 +962,7 @@
 
   /**
    * Set the open state of a tree node.
-   * 
+   *
    * @param cellList the CellList that changed state.
    * @param value the value to open
    * @param open true to open, false to close
@@ -1036,7 +1045,7 @@
 
   /**
    * Reduce the number of {@link HasData}s down to the specified level.
-   * 
+   *
    * @param level the level to trim to
    */
   private void trimToLevel(int level) {
diff --git a/user/src/com/google/gwt/user/cellview/client/CellList.java b/user/src/com/google/gwt/user/cellview/client/CellList.java
index 52df7d8..9412e6e 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellList.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellList.java
@@ -45,6 +45,19 @@
 /**
  * A single column list of cells.
  *
+ * <p>
+ * <h3>Examples</h3>
+ * <p>
+ * TODO example com.google.gwt.examples.cellview.CellListExample
+ * </p>
+ * <p>
+ * TODO example com.google.gwt.examples.cellview.CellListValueUpdaterExample
+ * </p>
+ * <p>
+ * TODO example com.google.gwt.examples.view.KeyProviderExample
+ * </p>
+ * </p>
+ *
  * @param <T> the data type of list items
  */
 public class CellList<T> extends AbstractHasData<T> {
@@ -259,7 +272,7 @@
 
   /**
    * Called when a user action triggers selection.
-   * 
+   *
    * @param event the event that triggered selection
    * @param value the value that was selected
    * @param indexOnPage the index of the value on the page
@@ -470,7 +483,7 @@
 
   /**
    * Called when the user selects a cell with the mouse or tab key.
-   * 
+   *
    * @param event the event
    * @param value the value that is selected
    * @param indexOnPage the index on the page
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTable.java b/user/src/com/google/gwt/user/cellview/client/CellTable.java
index 3bad38a..8c354a4 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTable.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -53,6 +53,19 @@
 /**
  * A list view that supports paging and columns.
  *
+ * <p>
+ * <h3>Examples</h3>
+ * <p>
+ * TODO example com.google.gwt.examples.cellview.CellTableExample
+ * </p>
+ * <p>
+ * TODO example com.google.gwt.examples.cellview.CellTableFieldUpdaterExample
+ * </p>
+ * <p>
+ * TODO example com.google.gwt.examples.view.KeyProviderExample
+ * </p>
+ * </p>
+ *
  * @param <T> the data type of each row
  */
 public class CellTable<T> extends AbstractHasData<T> {
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTree.java b/user/src/com/google/gwt/user/cellview/client/CellTree.java
index 3649cd6..9c549bf 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTree.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTree.java
@@ -52,6 +52,15 @@
  * the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
  * declaration.
  * </p>
+ *
+ * <p>
+ * <h3>Examples</h3>
+ * <dl>
+ * <dt>Trivial example</dt>
+ * <dd>TODO example com.google.gwt.examples.cellview.CellTreeExample</dd>
+ * <dt>Complex example</dt>
+ * <dd>TODO example com.google.gwt.examples.cellview.CellTreeExample2</dd>
+ * </dl>
  */
 public class CellTree extends AbstractCellTree implements HasAnimation,
     Focusable {
diff --git a/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java b/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java
index b1bb09f0..a3dacbc 100644
--- a/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java
+++ b/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java
@@ -269,7 +269,7 @@
    */
   private boolean pageStartChangedSinceRender;
 
-  private int rowCount = Integer.MIN_VALUE;
+  private int rowCount = 0;
 
   private boolean rowCountIsExact;
 
@@ -950,7 +950,7 @@
   private void updateLoadingState() {
     int cacheSize = rowData.size();
     int curPageSize = isRowCountExact() ? getCurrentPageSize() : pageSize;
-    if (rowCount == 0) {
+    if (rowCount == 0 && rowCountIsExact) {
       view.setLoadingState(LoadingState.EMPTY);
     } else if (cacheSize >= curPageSize) {
       view.setLoadingState(LoadingState.LOADED);
diff --git a/user/src/com/google/gwt/user/cellview/client/SimplePager.java b/user/src/com/google/gwt/user/cellview/client/SimplePager.java
index 64d51b7..dc16193 100644
--- a/user/src/com/google/gwt/user/cellview/client/SimplePager.java
+++ b/user/src/com/google/gwt/user/cellview/client/SimplePager.java
@@ -34,6 +34,11 @@
 /**
  * A pager for controlling a {@link HasRows} that only supports simple page
  * navigation.
+ *
+ * <p>
+ * <h3>Example</h3>
+ * TODO example com.google.gwt.examples.cellview.SimplePagerExample
+ * </p>
  */
 public class SimplePager extends AbstractPager {
 
diff --git a/user/src/com/google/gwt/app/client/DoubleBox.java b/user/src/com/google/gwt/user/client/ui/DoubleBox.java
similarity index 88%
rename from user/src/com/google/gwt/app/client/DoubleBox.java
rename to user/src/com/google/gwt/user/client/ui/DoubleBox.java
index 43ab5cf..960f0ca 100644
--- a/user/src/com/google/gwt/app/client/DoubleBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DoubleBox.java
@@ -13,10 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.ui.ValueBox;
+import com.google.gwt.text.client.DoubleParser;
+import com.google.gwt.text.client.DoubleRenderer;
 
 /**
  * <span style="color:red">Experimental API: This class is still under rapid
diff --git a/user/src/com/google/gwt/app/client/IntegerBox.java b/user/src/com/google/gwt/user/client/ui/IntegerBox.java
similarity index 88%
rename from user/src/com/google/gwt/app/client/IntegerBox.java
rename to user/src/com/google/gwt/user/client/ui/IntegerBox.java
index 3e762ff..0f6b1f6 100644
--- a/user/src/com/google/gwt/app/client/IntegerBox.java
+++ b/user/src/com/google/gwt/user/client/ui/IntegerBox.java
@@ -13,10 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.ui.ValueBox;
+import com.google.gwt.text.client.IntegerParser;
+import com.google.gwt.text.client.IntegerRenderer;
 
 /**
  * <span style="color:red">Experimental API: This class is still under rapid
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index 22a6daa..7c81449 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -19,7 +19,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.editor.client.IsEditor;
 import com.google.gwt.editor.client.LeafValueEditor;
-import com.google.gwt.editor.client.adapters.HasTextEditor;
+import com.google.gwt.editor.ui.client.adapters.HasTextEditor;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
diff --git a/user/src/com/google/gwt/app/client/LongBox.java b/user/src/com/google/gwt/user/client/ui/LongBox.java
similarity index 88%
rename from user/src/com/google/gwt/app/client/LongBox.java
rename to user/src/com/google/gwt/user/client/ui/LongBox.java
index a4e2d70..0121583 100644
--- a/user/src/com/google/gwt/app/client/LongBox.java
+++ b/user/src/com/google/gwt/user/client/ui/LongBox.java
@@ -13,10 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.ui.ValueBox;
+import com.google.gwt.text.client.LongParser;
+import com.google.gwt.text.client.LongRenderer;
 
 /**
  * <span style="color:red">Experimental API: This class is still under rapid
diff --git a/user/src/com/google/gwt/app/client/NotificationMole.java b/user/src/com/google/gwt/user/client/ui/NotificationMole.java
similarity index 96%
rename from user/src/com/google/gwt/app/client/NotificationMole.java
rename to user/src/com/google/gwt/user/client/ui/NotificationMole.java
index 9ba20f1..47a726f 100644
--- a/user/src/com/google/gwt/app/client/NotificationMole.java
+++ b/user/src/com/google/gwt/user/client/ui/NotificationMole.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.client;
+package com.google.gwt.user.client.ui;
 
 import com.google.gwt.animation.client.Animation;
 import com.google.gwt.core.client.GWT;
@@ -25,8 +25,6 @@
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
 
 /**
  * <p>
diff --git a/user/src/com/google/gwt/app/client/NotificationMole.ui.xml b/user/src/com/google/gwt/user/client/ui/NotificationMole.ui.xml
similarity index 100%
rename from user/src/com/google/gwt/app/client/NotificationMole.ui.xml
rename to user/src/com/google/gwt/user/client/ui/NotificationMole.ui.xml
diff --git a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
index eab38ab..9a710b2 100644
--- a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
@@ -16,27 +16,42 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Element;
-import com.google.gwt.text.shared.PassthroughParser;
-import com.google.gwt.text.shared.PassthroughRenderer;
+import com.google.gwt.text.shared.testing.PassthroughParser;
+import com.google.gwt.text.shared.testing.PassthroughRenderer;
 
 /**
- * Legacy abstract base class for all text entry widgets.
+ * Abstract base class for most text entry widgets.
+ * 
+ * <p>
+ * The names of the static members of {@link TextBoxBase}, as well as simple
+ * alignment names (<code>left</code>, <code>center</code>, <code>right</code>,
+ * <code>justify</code>), can be used as values for a <code>textAlignment</code>
+ * attribute.
+ * <p>
+ * For example,
+ * 
+ * <pre>
+ * &lt;g:TextBox textAlignment='ALIGN_RIGHT'/&gt;
+ * &lt;g:TextBox textAlignment='right'/&gt;
+ * </pre>
  */
-public class TextBoxBase extends ValueBoxBase<String>  {
+public class TextBoxBase extends ValueBoxBase<String> implements
+    SourcesChangeEvents {
 
   /**
-   * Text alignment constant, used in
-   * {@link TextBoxBase#setTextAlignment(TextBoxBase.TextAlignConstant)}.
+   * Legacy wrapper for {@link TextAlignment}, soon to be deprecated.
+   * @deprecated use {@link #setAlignment(TextAlignment)}
    */
+  @Deprecated
   public static class TextAlignConstant {
-    private String textAlignString;
+    private TextAlignment value;
 
-    private TextAlignConstant(String textAlignString) {
-      this.textAlignString = textAlignString;
+    private TextAlignConstant(TextAlignment value) {
+      this.value = value;
     }
 
-    String getTextAlignString() {
-      return textAlignString;
+    TextAlignment getTextAlignString() {
+      return value;
     }
   }
 
@@ -44,25 +59,25 @@
    * Center the text.
    */
   public static final TextAlignConstant ALIGN_CENTER = new TextAlignConstant(
-      "center");
+      TextAlignment.CENTER);
 
   /**
    * Justify the text.
    */
   public static final TextAlignConstant ALIGN_JUSTIFY = new TextAlignConstant(
-      "justify");
+      TextAlignment.JUSTIFY);
 
   /**
    * Align the text to the left edge.
    */
   public static final TextAlignConstant ALIGN_LEFT = new TextAlignConstant(
-      "left");
+      TextAlignment.LEFT);
 
   /**
    * Align the text to the right.
    */
   public static final TextAlignConstant ALIGN_RIGHT = new TextAlignConstant(
-      "right");
+      TextAlignment.RIGHT);
 
   /**
    * Creates a text box that wraps the given browser element handle. This is
@@ -75,6 +90,14 @@
   }
 
   /**
+   * @deprecated Use {@link #addChangeHandler} instead
+   */
+  @Deprecated
+  public void addChangeListener(ChangeListener listener) {
+    addChangeHandler(new ListenerWrapper.WrappedChangeListener(listener));
+  }
+
+  /**
    * Overridden to return "" from an empty text box.
    */
   @Override
@@ -82,4 +105,14 @@
     String raw = super.getValue();
     return raw == null ? "" : raw;
   }
+
+  /**
+   * Legacy wrapper for {@link #setAlignment(TextAlignment)}.
+   * 
+   * @deprecated use {@link #setAlignment(TextAlignment)}
+   */
+  @Deprecated
+  public void setTextAlignment(TextAlignConstant align) {
+    setAlignment(align.value);
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
index ed1dd09..d24f2a3 100644
--- a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
@@ -18,7 +18,7 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.editor.client.IsEditor;
-import com.google.gwt.editor.client.adapters.ValueBoxEditor;
+import com.google.gwt.editor.ui.client.adapters.ValueBoxEditor;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
 import com.google.gwt.event.dom.client.HasChangeHandlers;
@@ -34,48 +34,57 @@
 import com.google.gwt.text.shared.Renderer;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.TextBoxBase.TextAlignConstant;
 import com.google.gwt.user.client.ui.impl.TextBoxImpl;
 
 import java.text.ParseException;
 
 /**
- * <span style="color:red">Experimental API: This class is still under rapid
- * development, and is very likely to be deleted. Use it at your own risk.
- * </span>
- * <p>
  * Abstract base class for all text entry widgets.
  * 
  * <h3>Use in UiBinder Templates</h3>
  * 
- * <p>
- * The names of the static members of {@link TextBoxBase}, as well as simple
- * alignment names (<code>left</code>, <code>center</code>, <code>right</code>,
- * <code>justify</code>), can be used as values for a <code>textAlignment</code>
- * attribute.
- * <p>
- * For example,
- * 
- * <pre>
- * &lt;g:TextBox textAlignment='ALIGN_RIGHT'/&gt;
- * &lt;g:TextBox textAlignment='right'/&gt;
- * </pre>
- * 
  * @param <T> the value type
  */
 @SuppressWarnings("deprecation")
 public class ValueBoxBase<T> extends FocusWidget implements
-    SourcesChangeEvents, HasChangeHandlers, HasName, HasDirectionEstimator,
+    HasChangeHandlers, HasName, HasDirectionEstimator,
     HasValue<T>, AutoDirectionHandler.Target, IsEditor<ValueBoxEditor<T>> {
 
-  private static TextBoxImpl impl = GWT.create(TextBoxImpl.class);
+  /**
+   * Alignment values for {@link ValueBoxBase#setAlignment}.
+   */
+  public enum TextAlignment {
+    CENTER {
+      String getTextAlignString() {
+        return "center";
+      }
+    },
+    JUSTIFY {
+      String getTextAlignString() {
+        return "justify";
+      }
+    },
+    LEFT {
+      String getTextAlignString() {
+        return "left";
+      }
+    },
+    RIGHT {
+      String getTextAlignString() {
+        return "right";
+      }
 
+    };
+    abstract String getTextAlignString();
+  }
+
+  private static TextBoxImpl impl = GWT.create(TextBoxImpl.class);
   private final AutoDirectionHandler autoDirHandler;
 
   private final Parser<T> parser;
   private final Renderer<T> renderer;
-
   private Event currentEvent;
+
   private boolean valueChangeHandlerInitialized;
 
   /**
@@ -96,14 +105,6 @@
     return addDomHandler(handler, ChangeEvent.getType());
   }
 
-  /**
-   * @deprecated Use {@link #addChangeHandler} instead
-   */
-  @Deprecated
-  public void addChangeListener(ChangeListener listener) {
-    addChangeHandler(new ListenerWrapper.WrappedChangeListener(listener));
-  }
-
   public HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler) {
     // Initialization code
     if (!valueChangeHandlerInitialized) {
@@ -267,6 +268,10 @@
     }
   }
 
+  public void setAlignment(TextAlignment align) {
+    DOM.setStyleAttribute(getElement(), "textAlign", align.getTextAlignString());
+  }
+
   /**
    * Sets the cursor position.
    * 
@@ -358,7 +363,7 @@
     }
     impl.setSelectionRange(getElement(), pos, length);
   }
-
+  
   /**
    * Sets this object's text. Note that some browsers will manipulate the text
    * before adding it to the widget. For example, most browsers will strip all
@@ -373,18 +378,6 @@
     autoDirHandler.refreshDirection();
   }
 
-  /**
-   * Sets the alignment of the text in the text box.
-   * 
-   * @param align the text alignment (as specified by
-   *          {@link TextBoxBase#ALIGN_CENTER},
-   *          {@link TextBoxBase#ALIGN_JUSTIFY}, {@link TextBoxBase#ALIGN_LEFT},
-   *          and {@link TextBoxBase#ALIGN_RIGHT})
-   */
-  public void setTextAlignment(TextAlignConstant align) {
-    DOM.setStyleAttribute(getElement(), "textAlign", align.getTextAlignString());
-  }
-
   public void setValue(T value) {
     setValue(value, false);
   }
diff --git a/user/src/com/google/gwt/view/client/AsyncDataProvider.java b/user/src/com/google/gwt/view/client/AsyncDataProvider.java
index 78fcb9e..73cbf88 100644
--- a/user/src/com/google/gwt/view/client/AsyncDataProvider.java
+++ b/user/src/com/google/gwt/view/client/AsyncDataProvider.java
@@ -22,7 +22,8 @@
  * modified.
  *
  * <p>
- * Note: This class is new and its interface subject to change.
+ * <h3>Example</h3>
+ * TODO example com.google.gwt.examples.view.AsyncDataProviderExample
  * </p>
  *
  * @param <T> the data type of records in the list
diff --git a/user/src/com/google/gwt/view/client/ListDataProvider.java b/user/src/com/google/gwt/view/client/ListDataProvider.java
index 9674447..ca6df3b 100644
--- a/user/src/com/google/gwt/view/client/ListDataProvider.java
+++ b/user/src/com/google/gwt/view/client/ListDataProvider.java
@@ -30,7 +30,8 @@
  * in-memory list.
  *
  * <p>
- * Note: This class is new and its interface subject to change.
+ * <h3>Example</h3>
+ * TODO example com.google.gwt.examples.view.ListDataProviderExample
  * </p>
  *
  * @param <T> the data type of the list
diff --git a/user/test/com/google/gwt/app/AppSuite.java b/user/test/com/google/gwt/activity/ActivitySuite.java
similarity index 66%
rename from user/test/com/google/gwt/app/AppSuite.java
rename to user/test/com/google/gwt/activity/ActivitySuite.java
index af744ed..cf43d25 100644
--- a/user/test/com/google/gwt/app/AppSuite.java
+++ b/user/test/com/google/gwt/activity/ActivitySuite.java
@@ -13,21 +13,20 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app;
+package com.google.gwt.activity;
 
-import com.google.gwt.app.place.impl.PlaceHistoryMapperGeneratorTest;
-import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.activity.shared.ActivityManagerTest;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 /**
- * Suite of app package tests that require GWT.
+ * Tests of the activity package.
  */
-public class AppSuite {
+public class ActivitySuite {
   public static Test suite() {
-    TestSuite suite = new GWTTestSuite("app package tests that require GWT");
-    suite.addTestSuite(PlaceHistoryMapperGeneratorTest.class);
+    TestSuite suite = new TestSuite("Tests of the activity package");
+    suite.addTestSuite(ActivityManagerTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/app/place/ActivityManagerTest.java b/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
similarity index 98%
rename from user/test/com/google/gwt/app/place/ActivityManagerTest.java
rename to user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
index 0410922..d5d47d0 100644
--- a/user/test/com/google/gwt/app/place/ActivityManagerTest.java
+++ b/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
@@ -13,13 +13,16 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.activity.shared;
 
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
 import com.google.gwt.event.shared.UmbrellaException;
 import com.google.gwt.event.shared.testing.CountingEventBus;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceChangeEvent;
+import com.google.gwt.place.shared.PlaceChangeRequestEvent;
 import com.google.gwt.user.client.ui.AcceptsOneWidget;
 import com.google.gwt.user.client.ui.IsWidget;
 import com.google.gwt.user.client.ui.Widget;
diff --git a/user/test/com/google/gwt/place/PlaceSuite.gwt.xml b/user/test/com/google/gwt/place/PlaceSuite.gwt.xml
new file mode 100644
index 0000000..44c1d91
--- /dev/null
+++ b/user/test/com/google/gwt/place/PlaceSuite.gwt.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
+<module>
+  <inherits name='com.google.gwt.place.Place'/>
+
+  <source path="testplaces"/>
+  <source path="testplacemappers"/>
+</module>
diff --git a/user/test/com/google/gwt/app/AppJreSuite.java b/user/test/com/google/gwt/place/PlaceSuite.java
similarity index 61%
rename from user/test/com/google/gwt/app/AppJreSuite.java
rename to user/test/com/google/gwt/place/PlaceSuite.java
index 5708bf5..e9aa7e8 100644
--- a/user/test/com/google/gwt/app/AppJreSuite.java
+++ b/user/test/com/google/gwt/place/PlaceSuite.java
@@ -13,24 +13,25 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app;
+package com.google.gwt.place;
 
-import com.google.gwt.app.place.ActivityManagerTest;
-import com.google.gwt.app.place.PlaceChangeRequestEventTest;
-import com.google.gwt.app.place.PlaceControllerTest;
-import com.google.gwt.app.place.PlaceHistoryHandlerTest;
-import com.google.gwt.app.rebind.PlaceHistoryGeneratorContextTest;
+import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.place.impl.PlaceHistoryMapperGeneratorTest;
+import com.google.gwt.place.rebind.PlaceHistoryGeneratorContextTest;
+import com.google.gwt.place.shared.PlaceChangeRequestEventTest;
+import com.google.gwt.place.shared.PlaceControllerTest;
+import com.google.gwt.place.shared.PlaceHistoryHandlerTest;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 /**
- * Suite of app package tests that require the JRE.
+ * Tests of the place package.
  */
-public class AppJreSuite {
+public class PlaceSuite {
   public static Test suite() {
-    TestSuite suite = new TestSuite("app package tests that require the JRE");
-    suite.addTestSuite(ActivityManagerTest.class);
+    TestSuite suite = new GWTTestSuite("Tests of the place package");
+    suite.addTestSuite(PlaceHistoryMapperGeneratorTest.class);
     suite.addTestSuite(PlaceControllerTest.class);
     suite.addTestSuite(PlaceChangeRequestEventTest.class);
     suite.addTestSuite(PlaceHistoryGeneratorContextTest.class);
diff --git a/user/test/com/google/gwt/app/place/impl/PlaceHistoryMapperGeneratorTest.java b/user/test/com/google/gwt/place/impl/PlaceHistoryMapperGeneratorTest.java
similarity index 81%
rename from user/test/com/google/gwt/app/place/impl/PlaceHistoryMapperGeneratorTest.java
rename to user/test/com/google/gwt/place/impl/PlaceHistoryMapperGeneratorTest.java
index b7a0daa..f3061f1 100644
--- a/user/test/com/google/gwt/app/place/impl/PlaceHistoryMapperGeneratorTest.java
+++ b/user/test/com/google/gwt/place/impl/PlaceHistoryMapperGeneratorTest.java
@@ -13,25 +13,25 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.impl;
+package com.google.gwt.place.impl;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceHistoryMapper;
-import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;
-import com.google.gwt.app.place.WithTokenizers;
-import com.google.gwt.app.place.testplacemappers.NoFactory;
-import com.google.gwt.app.place.testplacemappers.WithFactory;
-import com.google.gwt.app.place.testplaces.Place1;
-import com.google.gwt.app.place.testplaces.Place2;
-import com.google.gwt.app.place.testplaces.Place3;
-import com.google.gwt.app.place.testplaces.Place4;
-import com.google.gwt.app.place.testplaces.Place5;
-import com.google.gwt.app.place.testplaces.Tokenizer2;
-import com.google.gwt.app.place.testplaces.Tokenizer3;
-import com.google.gwt.app.place.testplaces.Tokenizer4;
-import com.google.gwt.app.place.testplaces.TokenizerFactory;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceHistoryMapper;
+import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
+import com.google.gwt.place.shared.WithTokenizers;
+import com.google.gwt.place.testplacemappers.NoFactory;
+import com.google.gwt.place.testplacemappers.WithFactory;
+import com.google.gwt.place.testplaces.Place1;
+import com.google.gwt.place.testplaces.Place2;
+import com.google.gwt.place.testplaces.Place3;
+import com.google.gwt.place.testplaces.Place4;
+import com.google.gwt.place.testplaces.Place5;
+import com.google.gwt.place.testplaces.Tokenizer2;
+import com.google.gwt.place.testplaces.Tokenizer3;
+import com.google.gwt.place.testplaces.Tokenizer4;
+import com.google.gwt.place.testplaces.TokenizerFactory;
 
 /**
  * Functional test of PlaceHistoryMapperGenerator.
@@ -50,7 +50,7 @@
 
   @Override
   public String getModuleName() {
-    return "com.google.gwt.app.App";
+    return "com.google.gwt.place.PlaceSuite";
   }
 
   Place1 place1 = new Place1("able");
diff --git a/user/test/com/google/gwt/app/rebind/EmptyMockJavaResource.java b/user/test/com/google/gwt/place/rebind/EmptyMockJavaResource.java
similarity index 97%
rename from user/test/com/google/gwt/app/rebind/EmptyMockJavaResource.java
rename to user/test/com/google/gwt/place/rebind/EmptyMockJavaResource.java
index eb3c5d3..588b059 100644
--- a/user/test/com/google/gwt/app/rebind/EmptyMockJavaResource.java
+++ b/user/test/com/google/gwt/place/rebind/EmptyMockJavaResource.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
 import com.google.gwt.dev.javac.impl.MockJavaResource;
 
diff --git a/user/test/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java b/user/test/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java
similarity index 83%
rename from user/test/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java
rename to user/test/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java
index 8f5dcbe..ac66a88 100644
--- a/user/test/com/google/gwt/app/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java
+++ b/user/test/com/google/gwt/place/rebind/MostToLeastDerivedPlaceTypeComparatorTest.java
@@ -13,16 +13,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.Prefix;
-import com.google.gwt.app.place.testplaces.Place1;
-import com.google.gwt.app.place.testplaces.Place2;
-import com.google.gwt.app.place.testplaces.Place3;
-import com.google.gwt.app.place.testplaces.Place4;
-import com.google.gwt.app.place.testplaces.Place5;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
@@ -31,6 +23,14 @@
 import com.google.gwt.dev.javac.impl.JavaResourceBase;
 import com.google.gwt.dev.resource.Resource;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
+import com.google.gwt.place.testplaces.Place1;
+import com.google.gwt.place.testplaces.Place2;
+import com.google.gwt.place.testplaces.Place3;
+import com.google.gwt.place.testplaces.Place4;
+import com.google.gwt.place.testplaces.Place5;
 
 import junit.framework.TestCase;
 
@@ -73,17 +73,17 @@
         getJavaResources());
     typeOracle = state.getTypeOracle();
 
-    place = typeOracle.getType("com.google.gwt.app.place.Place");
+    place = typeOracle.getType("com.google.gwt.app.place.shared.Place");
     assertNotNull(place);
-    place1 = typeOracle.getType("com.google.gwt.app.place.testplaces.Place1");
+    place1 = typeOracle.getType("com.google.gwt.app.place.shared.testplaces.Place1");
     assertNotNull(place1);
-    place2 = typeOracle.getType("com.google.gwt.app.place.testplaces.Place2");
+    place2 = typeOracle.getType("com.google.gwt.app.place.shared.testplaces.Place2");
     assertNotNull(place2);
-    place3 = typeOracle.getType("com.google.gwt.app.place.testplaces.Place3");
+    place3 = typeOracle.getType("com.google.gwt.app.place.shared.testplaces.Place3");
     assertNotNull(place3);
-    place4 = typeOracle.getType("com.google.gwt.app.place.testplaces.Place4");
+    place4 = typeOracle.getType("com.google.gwt.app.place.shared.testplaces.Place4");
     assertNotNull(place4);
-    place5 = typeOracle.getType("com.google.gwt.app.place.testplaces.Place5");
+    place5 = typeOracle.getType("com.google.gwt.app.place.shared.testplaces.Place5");
     assertNotNull(place5);
   }
 
diff --git a/user/test/com/google/gwt/app/rebind/PlaceHistoryGeneratorContextTest.java b/user/test/com/google/gwt/place/rebind/PlaceHistoryGeneratorContextTest.java
similarity index 87%
rename from user/test/com/google/gwt/app/rebind/PlaceHistoryGeneratorContextTest.java
rename to user/test/com/google/gwt/place/rebind/PlaceHistoryGeneratorContextTest.java
index c188e13..7855f62 100644
--- a/user/test/com/google/gwt/app/rebind/PlaceHistoryGeneratorContextTest.java
+++ b/user/test/com/google/gwt/place/rebind/PlaceHistoryGeneratorContextTest.java
@@ -13,24 +13,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceHistoryMapper;
-import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.Prefix;
-import com.google.gwt.app.place.WithTokenizers;
-import com.google.gwt.app.place.testplacemappers.NoFactory;
-import com.google.gwt.app.place.testplacemappers.WithFactory;
-import com.google.gwt.app.place.testplaces.Place1;
-import com.google.gwt.app.place.testplaces.Place2;
-import com.google.gwt.app.place.testplaces.Place3;
-import com.google.gwt.app.place.testplaces.Place4;
-import com.google.gwt.app.place.testplaces.Tokenizer2;
-import com.google.gwt.app.place.testplaces.Tokenizer3;
-import com.google.gwt.app.place.testplaces.Tokenizer4;
-import com.google.gwt.app.place.testplaces.TokenizerFactory;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -43,6 +27,22 @@
 import com.google.gwt.dev.resource.Resource;
 import com.google.gwt.dev.util.UnitTestTreeLogger;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceHistoryMapper;
+import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
+import com.google.gwt.place.shared.WithTokenizers;
+import com.google.gwt.place.testplacemappers.NoFactory;
+import com.google.gwt.place.testplacemappers.WithFactory;
+import com.google.gwt.place.testplaces.Place1;
+import com.google.gwt.place.testplaces.Place2;
+import com.google.gwt.place.testplaces.Place3;
+import com.google.gwt.place.testplaces.Place4;
+import com.google.gwt.place.testplaces.Tokenizer2;
+import com.google.gwt.place.testplaces.Tokenizer3;
+import com.google.gwt.place.testplaces.Tokenizer4;
+import com.google.gwt.place.testplaces.TokenizerFactory;
 
 import junit.framework.TestCase;
 
@@ -197,11 +197,11 @@
       protected CharSequence getContent() {
         StringBuilder code = new StringBuilder();
         code.append("package my;\n");
-        code.append("import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;\n");
-        code.append("import com.google.gwt.app.place.WithTokenizers;\n");
-        code.append("import com.google.gwt.app.place.Prefix;\n");
-        code.append("import com.google.gwt.app.place.testplaces.Place1;\n");
-        code.append("import com.google.gwt.app.place.testplaces.Tokenizer2;\n");
+        code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n");
+        code.append("import com.google.gwt.place.shared.WithTokenizers;\n");
+        code.append("import com.google.gwt.place.shared.Prefix;\n");
+        code.append("import com.google.gwt.place.testplaces.Place1;\n");
+        code.append("import com.google.gwt.place.testplaces.Tokenizer2;\n");
 
         code.append("@WithTokenizers(Place1.Tokenizer.class)\n");
         code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n");
@@ -242,11 +242,11 @@
       protected CharSequence getContent() {
         StringBuilder code = new StringBuilder();
         code.append("package my;\n");
-        code.append("import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;\n");
-        code.append("import com.google.gwt.app.place.PlaceTokenizer;\n");
-        code.append("import com.google.gwt.app.place.WithTokenizers;\n");
-        code.append("import com.google.gwt.app.place.Prefix;\n");
-        code.append("import com.google.gwt.app.place.testplaces.Place1;\n");
+        code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n");
+        code.append("import com.google.gwt.place.shared.PlaceTokenizer;\n");
+        code.append("import com.google.gwt.place.shared.WithTokenizers;\n");
+        code.append("import com.google.gwt.place.shared.Prefix;\n");
+        code.append("import com.google.gwt.place.testplaces.Place1;\n");
 
         code.append("@WithTokenizers(Place1.Tokenizer.class)\n");
         code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n");
@@ -288,10 +288,10 @@
       protected CharSequence getContent() {
         StringBuilder code = new StringBuilder();
         code.append("package my;\n");
-        code.append("import com.google.gwt.app.place.Place;\n");
-        code.append("import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;\n");
-        code.append("import com.google.gwt.app.place.PlaceTokenizer;\n");
-        code.append("import com.google.gwt.app.place.Prefix;\n");
+        code.append("import com.google.gwt.place.shared.Place;\n");
+        code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n");
+        code.append("import com.google.gwt.place.shared.PlaceTokenizer;\n");
+        code.append("import com.google.gwt.place.shared.Prefix;\n");
 
         code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n");
         code.append("  interface Factory {\n");
diff --git a/user/test/com/google/gwt/app/rebind/RealJavaResource.java b/user/test/com/google/gwt/place/rebind/RealJavaResource.java
similarity index 97%
rename from user/test/com/google/gwt/app/rebind/RealJavaResource.java
rename to user/test/com/google/gwt/place/rebind/RealJavaResource.java
index a18e161..d527758 100644
--- a/user/test/com/google/gwt/app/rebind/RealJavaResource.java
+++ b/user/test/com/google/gwt/place/rebind/RealJavaResource.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.rebind;
+package com.google.gwt.place.rebind;
 
 import com.google.gwt.dev.javac.impl.MockJavaResource;
 import com.google.gwt.dev.util.Util;
diff --git a/user/test/com/google/gwt/app/place/MockPlaceControllerDelegate.java b/user/test/com/google/gwt/place/shared/MockPlaceControllerDelegate.java
similarity index 97%
rename from user/test/com/google/gwt/app/place/MockPlaceControllerDelegate.java
rename to user/test/com/google/gwt/place/shared/MockPlaceControllerDelegate.java
index 72964e9..7bb2ff0 100644
--- a/user/test/com/google/gwt/app/place/MockPlaceControllerDelegate.java
+++ b/user/test/com/google/gwt/place/shared/MockPlaceControllerDelegate.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.Window.ClosingEvent;
diff --git a/user/test/com/google/gwt/app/place/PlaceChangeRequestEventTest.java b/user/test/com/google/gwt/place/shared/PlaceChangeRequestEventTest.java
similarity index 96%
rename from user/test/com/google/gwt/app/place/PlaceChangeRequestEventTest.java
rename to user/test/com/google/gwt/place/shared/PlaceChangeRequestEventTest.java
index 0c121c2..46df9d9 100644
--- a/user/test/com/google/gwt/app/place/PlaceChangeRequestEventTest.java
+++ b/user/test/com/google/gwt/place/shared/PlaceChangeRequestEventTest.java
@@ -13,7 +13,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
+
 
 import junit.framework.TestCase;
 
diff --git a/user/test/com/google/gwt/app/place/PlaceControllerTest.java b/user/test/com/google/gwt/place/shared/PlaceControllerTest.java
similarity index 98%
rename from user/test/com/google/gwt/app/place/PlaceControllerTest.java
rename to user/test/com/google/gwt/place/shared/PlaceControllerTest.java
index 6034c77..c3f133d 100644
--- a/user/test/com/google/gwt/app/place/PlaceControllerTest.java
+++ b/user/test/com/google/gwt/place/shared/PlaceControllerTest.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.SimpleEventBus;
diff --git a/user/test/com/google/gwt/app/place/PlaceHistoryHandlerTest.java b/user/test/com/google/gwt/place/shared/PlaceHistoryHandlerTest.java
similarity index 95%
rename from user/test/com/google/gwt/app/place/PlaceHistoryHandlerTest.java
rename to user/test/com/google/gwt/place/shared/PlaceHistoryHandlerTest.java
index 5306086..05846c7 100644
--- a/user/test/com/google/gwt/app/place/PlaceHistoryHandlerTest.java
+++ b/user/test/com/google/gwt/place/shared/PlaceHistoryHandlerTest.java
@@ -13,15 +13,16 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place;
+package com.google.gwt.place.shared;
 
-import com.google.gwt.app.place.testplaces.Place1;
-import com.google.gwt.app.place.testplaces.Place2;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.event.shared.SimpleEventBus;
+import com.google.gwt.place.shared.PlaceHistoryHandler.Historian;
+import com.google.gwt.place.testplaces.Place1;
+import com.google.gwt.place.testplaces.Place2;
 
 import junit.framework.TestCase;
 
diff --git a/user/test/com/google/gwt/app/place/testplacemappers/NoFactory.java b/user/test/com/google/gwt/place/testplacemappers/NoFactory.java
similarity index 62%
rename from user/test/com/google/gwt/app/place/testplacemappers/NoFactory.java
rename to user/test/com/google/gwt/place/testplacemappers/NoFactory.java
index 6c36148..39ef9e9 100644
--- a/user/test/com/google/gwt/app/place/testplacemappers/NoFactory.java
+++ b/user/test/com/google/gwt/place/testplacemappers/NoFactory.java
@@ -13,17 +13,17 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplacemappers;
+package com.google.gwt.place.testplacemappers;
 
-import com.google.gwt.app.place.PlaceHistoryMapper;
-import com.google.gwt.app.place.WithTokenizers;
-import com.google.gwt.app.place.testplaces.Place1;
-import com.google.gwt.app.place.testplaces.Tokenizer2;
-import com.google.gwt.app.place.testplaces.Tokenizer3;
-import com.google.gwt.app.place.testplaces.Tokenizer4;
+import com.google.gwt.place.shared.PlaceHistoryMapper;
+import com.google.gwt.place.shared.WithTokenizers;
+import com.google.gwt.place.testplaces.Place1;
+import com.google.gwt.place.testplaces.Tokenizer2;
+import com.google.gwt.place.testplaces.Tokenizer3;
+import com.google.gwt.place.testplaces.Tokenizer4;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 @WithTokenizers({
   Place1.Tokenizer.class, Tokenizer2.class, Tokenizer3.class,
diff --git a/user/test/com/google/gwt/app/place/testplacemappers/WithFactory.java b/user/test/com/google/gwt/place/testplacemappers/WithFactory.java
similarity index 66%
rename from user/test/com/google/gwt/app/place/testplacemappers/WithFactory.java
rename to user/test/com/google/gwt/place/testplacemappers/WithFactory.java
index bdcb6f1..29976a9 100644
--- a/user/test/com/google/gwt/app/place/testplacemappers/WithFactory.java
+++ b/user/test/com/google/gwt/place/testplacemappers/WithFactory.java
@@ -13,15 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplacemappers;
+package com.google.gwt.place.testplacemappers;
 
-import com.google.gwt.app.place.PlaceHistoryMapperWithFactory;
-import com.google.gwt.app.place.WithTokenizers;
-import com.google.gwt.app.place.testplaces.Tokenizer4;
-import com.google.gwt.app.place.testplaces.TokenizerFactory;
+import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
+import com.google.gwt.place.shared.WithTokenizers;
+import com.google.gwt.place.testplaces.Tokenizer4;
+import com.google.gwt.place.testplaces.TokenizerFactory;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 @WithTokenizers(Tokenizer4.class)
 public interface WithFactory extends
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place1.java b/user/test/com/google/gwt/place/testplaces/Place1.java
similarity index 80%
rename from user/test/com/google/gwt/app/place/testplaces/Place1.java
rename to user/test/com/google/gwt/place/testplaces/Place1.java
index 0e4dd55..587b182 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place1.java
+++ b/user/test/com/google/gwt/place/testplaces/Place1.java
@@ -13,14 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.Place;
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.Prefix;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Place1 extends Place {
   public final String content;
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place2.java b/user/test/com/google/gwt/place/testplaces/Place2.java
similarity index 81%
rename from user/test/com/google/gwt/app/place/testplaces/Place2.java
rename to user/test/com/google/gwt/place/testplaces/Place2.java
index 425a5bb..c272aa9 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place2.java
+++ b/user/test/com/google/gwt/place/testplaces/Place2.java
@@ -13,12 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.Place;
+import com.google.gwt.place.shared.Place;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Place2 extends Place {
   public final String content;
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place3.java b/user/test/com/google/gwt/place/testplaces/Place3.java
similarity index 84%
rename from user/test/com/google/gwt/app/place/testplaces/Place3.java
rename to user/test/com/google/gwt/place/testplaces/Place3.java
index 2ec0c64..5092a2b 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place3.java
+++ b/user/test/com/google/gwt/place/testplaces/Place3.java
@@ -13,10 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Place3 extends Place1 {
 
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place4.java b/user/test/com/google/gwt/place/testplaces/Place4.java
similarity index 84%
rename from user/test/com/google/gwt/app/place/testplaces/Place4.java
rename to user/test/com/google/gwt/place/testplaces/Place4.java
index 3c98fee..37a976d 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place4.java
+++ b/user/test/com/google/gwt/place/testplaces/Place4.java
@@ -13,10 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Place4 extends Place1 {
 
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place5.java b/user/test/com/google/gwt/place/testplaces/Place5.java
similarity index 84%
rename from user/test/com/google/gwt/app/place/testplaces/Place5.java
rename to user/test/com/google/gwt/place/testplaces/Place5.java
index 47bfb1a..8df3e12 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place5.java
+++ b/user/test/com/google/gwt/place/testplaces/Place5.java
@@ -13,10 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Place5 extends Place3 {
 
diff --git a/user/test/com/google/gwt/app/place/testplaces/Tokenizer2.java b/user/test/com/google/gwt/place/testplaces/Tokenizer2.java
similarity index 81%
rename from user/test/com/google/gwt/app/place/testplaces/Tokenizer2.java
rename to user/test/com/google/gwt/place/testplaces/Tokenizer2.java
index dc3d772..520efd7 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Tokenizer2.java
+++ b/user/test/com/google/gwt/place/testplaces/Tokenizer2.java
@@ -13,12 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.PlaceTokenizer;
+import com.google.gwt.place.shared.PlaceTokenizer;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Tokenizer2 implements PlaceTokenizer<Place2> {
   public Place2 getPlace(String token) {
diff --git a/user/test/com/google/gwt/app/place/testplaces/Tokenizer3.java b/user/test/com/google/gwt/place/testplaces/Tokenizer3.java
similarity index 81%
rename from user/test/com/google/gwt/app/place/testplaces/Tokenizer3.java
rename to user/test/com/google/gwt/place/testplaces/Tokenizer3.java
index f8a129a..854e488 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Tokenizer3.java
+++ b/user/test/com/google/gwt/place/testplaces/Tokenizer3.java
@@ -13,12 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.PlaceTokenizer;
+import com.google.gwt.place.shared.PlaceTokenizer;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Tokenizer3 implements PlaceTokenizer<Place3> {
 
diff --git a/user/test/com/google/gwt/app/place/testplaces/Tokenizer4.java b/user/test/com/google/gwt/place/testplaces/Tokenizer4.java
similarity index 81%
rename from user/test/com/google/gwt/app/place/testplaces/Tokenizer4.java
rename to user/test/com/google/gwt/place/testplaces/Tokenizer4.java
index 089ca8c..7f41635 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Tokenizer4.java
+++ b/user/test/com/google/gwt/place/testplaces/Tokenizer4.java
@@ -13,12 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.PlaceTokenizer;
+import com.google.gwt.place.shared.PlaceTokenizer;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class Tokenizer4 implements PlaceTokenizer<Place4> {
   public Place4 getPlace(String token) {
diff --git a/user/test/com/google/gwt/app/place/testplaces/TokenizerFactory.java b/user/test/com/google/gwt/place/testplaces/TokenizerFactory.java
similarity index 83%
rename from user/test/com/google/gwt/app/place/testplaces/TokenizerFactory.java
rename to user/test/com/google/gwt/place/testplaces/TokenizerFactory.java
index 60046b4..24210b5 100644
--- a/user/test/com/google/gwt/app/place/testplaces/TokenizerFactory.java
+++ b/user/test/com/google/gwt/place/testplaces/TokenizerFactory.java
@@ -13,13 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.place.testplaces;
 
-import com.google.gwt.app.place.PlaceTokenizer;
-import com.google.gwt.app.place.Prefix;
+import com.google.gwt.place.shared.PlaceTokenizer;
+import com.google.gwt.place.shared.Prefix;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Used by tests of {@link com.google.gwt.place.rebind.PlaceHistoryMapperGenerator}.
  */
 public class TokenizerFactory {
   public static final String PLACE2_PREFIX = "p2";
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
index 1f71e90..a6ad74a 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
@@ -16,6 +16,7 @@
 package com.google.gwt.requestfactory;
 
 import com.google.gwt.requestfactory.client.impl.SimpleEntityProxyIdTest;
+import com.google.gwt.requestfactory.rebind.model.RequestFactoryModelTest;
 import com.google.gwt.requestfactory.server.JsonRequestProcessorTest;
 import com.google.gwt.requestfactory.server.ReflectionBasedOperationRegistryTest;
 import com.google.gwt.requestfactory.server.RequestPropertyTest;
@@ -33,6 +34,7 @@
     suite.addTestSuite(SimpleEntityProxyIdTest.class);
     suite.addTestSuite(JsonRequestProcessorTest.class);
     suite.addTestSuite(ReflectionBasedOperationRegistryTest.class);
+    suite.addTestSuite(RequestFactoryModelTest.class);
     suite.addTestSuite(RequestPropertyTest.class);
     return suite;
   }
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
index b99fc29..44de728 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
@@ -16,11 +16,11 @@
 package com.google.gwt.requestfactory;
 
 import com.google.gwt.junit.tools.GWTTestSuite;
-import com.google.gwt.requestfactory.client.EditorTest;
 import com.google.gwt.requestfactory.client.FindServiceTest;
 import com.google.gwt.requestfactory.client.RequestFactoryExceptionHandlerTest;
 import com.google.gwt.requestfactory.client.RequestFactoryStringTest;
 import com.google.gwt.requestfactory.client.RequestFactoryTest;
+import com.google.gwt.requestfactory.client.ui.EditorTest;
 
 import junit.framework.Test;
 
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
index 8917683..fa7c212 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
@@ -164,6 +164,50 @@
     });
   }
 
+  public void testFindFindEdit() {
+    delayTestFinish(5000);
+
+    final SimpleFooEventHandler<SimpleFooStringProxy> handler = new SimpleFooEventHandler<SimpleFooStringProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooStringProxy.class, handler);
+
+    req.simpleFooStringRequest().findSimpleFooStringById("999x").fire(
+        new Receiver<SimpleFooStringProxy>() {
+
+          @Override
+          public void onSuccess(SimpleFooStringProxy newFoo) {
+            assertEquals(1, handler.updateEventCount);
+            assertEquals(1, handler.totalEventCount);
+
+            req.simpleFooStringRequest().findSimpleFooStringById("999x").fire(
+                new Receiver<SimpleFooStringProxy>() {
+
+                  @Override
+                  public void onSuccess(SimpleFooStringProxy newFoo) {
+                    // no events are fired second time.
+                    assertEquals(1, handler.updateEventCount);
+                    assertEquals(1, handler.totalEventCount);
+                    SimpleFooStringRequest context = req.simpleFooStringRequest();
+                    final Request<Void> mutateRequest = context.persist().using(
+                        newFoo);
+                    newFoo = context.edit(newFoo);
+                    newFoo.setUserName("Ray");
+                    mutateRequest.fire(new Receiver<Void>() {
+                      @Override
+                      public void onSuccess(Void response) {
+                        // events fired on updates.
+                        assertEquals(2, handler.updateEventCount);
+                        assertEquals(2, handler.totalEventCount);
+
+                        finishTestAndReset();
+                      }
+                    });
+                  }
+                });
+          }
+        });
+  }
+
   public void testFetchEntity() {
     delayTestFinish(5000);
     req.simpleFooStringRequest().findSimpleFooStringById("999x").fire(
@@ -275,8 +319,8 @@
                       @Override
                       public void onSuccess(SimpleFooStringProxy finalFoo) {
                         assertEquals("Ray", finalFoo.getUserName());
-                        assertEquals(3, handler.updateEventCount);
-                        assertEquals(3, handler.totalEventCount);
+                        assertEquals(2, handler.updateEventCount);
+                        assertEquals(2, handler.totalEventCount);
                         finishTestAndReset();
                       }
                     });
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index d83dafa..d454685 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -42,7 +42,6 @@
  * Tests for {@link com.google.gwt.requestfactory.shared.RequestFactory}.
  */
 public class RequestFactoryTest extends RequestFactoryTestBase {
-  private static final int DELAY_TEST_FINISH = 5000;
 
   /*
    * DO NOT USE finishTest(). Instead, call finishTestAndReset();
@@ -168,14 +167,17 @@
     }
   }
 
+  private static final int DELAY_TEST_FINISH = 5000;
+
   public <T extends EntityProxy> void assertContains(Collection<T> col, T value) {
     for (T x : col) {
       if (x.stableId().equals(value.stableId())) {
         return;
       }
     }
-    assertTrue(("Value " + value + " not found in collection ")
-        + col.toString(), false);
+    assertTrue(
+        ("Value " + value + " not found in collection ") + col.toString(),
+        false);
   }
 
   public <T extends EntityProxy> void assertNotContains(Collection<T> col,
@@ -185,12 +187,132 @@
     }
   }
 
+  public void disabled_testEchoComplexFutures() {
+    // relate futures on the server. Check if the relationship is still present
+    // on the client.
+    delayTestFinish(DELAY_TEST_FINISH);
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
+    SimpleFooRequest context = req.simpleFooRequest();
+    final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
+    final SimpleBarProxy simpleBar = context.create(SimpleBarProxy.class);
+    context.echoComplex(simpleFoo, simpleBar).fire(
+        new Receiver<SimpleFooProxy>() {
+          @Override
+          public void onSuccess(SimpleFooProxy response) {
+            assertEquals(0, handler.totalEventCount);
+            checkStableIdEquals(simpleFoo, response);
+            SimpleBarProxy responseBar = response.getBarField();
+            assertNotNull(responseBar);
+            checkStableIdEquals(simpleBar, responseBar);
+            finishTestAndReset();
+          }
+        });
+  }
+
+  public void disabled_testEchoSimpleFutures() {
+    // tests if futureIds can be echoed back.
+    delayTestFinish(DELAY_TEST_FINISH);
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
+    SimpleFooRequest context = req.simpleFooRequest();
+    final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
+    context.echo(simpleFoo).fire(new Receiver<SimpleFooProxy>() {
+      @Override
+      public void onSuccess(SimpleFooProxy response) {
+        assertEquals(0, handler.totalEventCount);
+        checkStableIdEquals(simpleFoo, response);
+        finishTestAndReset();
+      }
+    });
+  }
+
+  /**
+   * Test that removing a parent entity and implicitly removing the child sends
+   * an event to the client that the child was removed.
+   * 
+   * TODO(rjrjr): Should cascading deletes be detected?
+   */
+  public void disableTestMethodWithSideEffectDeleteChild() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    // Persist bar.
+    SimpleBarRequest context = req.simpleBarRequest();
+    final SimpleBarProxy bar = context.create(SimpleBarProxy.class);
+    context.persistAndReturnSelf().using(bar).fire(
+        new Receiver<SimpleBarProxy>() {
+          @Override
+          public void onSuccess(SimpleBarProxy persistentBar) {
+            // Persist foo with bar as a child.
+            SimpleFooRequest context = req.simpleFooRequest();
+            SimpleFooProxy foo = context.create(SimpleFooProxy.class);
+            final Request<SimpleFooProxy> persistRequest = context.persistAndReturnSelf().using(
+                foo);
+            foo = context.edit(foo);
+            foo.setUserName("John");
+            foo.setBarField(bar);
+            persistRequest.fire(new Receiver<SimpleFooProxy>() {
+              @Override
+              public void onSuccess(SimpleFooProxy persistentFoo) {
+                // Handle changes to SimpleFooProxy.
+                final SimpleFooEventHandler<SimpleFooProxy> fooHandler = new SimpleFooEventHandler<SimpleFooProxy>();
+                EntityProxyChange.registerForProxyType(req.getEventBus(),
+                    SimpleFooProxy.class, fooHandler);
+
+                // Handle changes to SimpleBarProxy.
+                final SimpleFooEventHandler<SimpleBarProxy> barHandler = new SimpleFooEventHandler<SimpleBarProxy>();
+                EntityProxyChange.registerForProxyType(req.getEventBus(),
+                    SimpleBarProxy.class, barHandler);
+
+                // Delete bar.
+                SimpleFooRequest context = req.simpleFooRequest();
+                final Request<Void> deleteRequest = context.deleteBar().using(
+                    persistentFoo);
+                SimpleFooProxy editable = context.edit(persistentFoo);
+                editable.setBarField(bar);
+                deleteRequest.fire(new Receiver<Void>() {
+                  @Override
+                  public void onSuccess(Void response) {
+                    assertEquals(1, fooHandler.updateEventCount); // set bar to
+                    // null
+                    assertEquals(1, fooHandler.totalEventCount);
+
+                    assertEquals(1, barHandler.deleteEventCount); // deleted bar
+                    assertEquals(1, barHandler.totalEventCount);
+                    finishTestAndReset();
+                  }
+                });
+              }
+            });
+          }
+        });
+  }
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.requestfactory.RequestFactorySuite";
   }
 
   /**
+   * Test that the same object, referenced twice, points to the same instance.
+   */
+  public void testAntiAliasing() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().fetchDoubleReference().with("fooField",
+        "selfOneToManyField").fire(new Receiver<SimpleFooProxy>() {
+      @Override
+      public void onSuccess(SimpleFooProxy response) {
+        assertNotNull(response.getFooField());
+        assertSame(response.getFooField(),
+            response.getSelfOneToManyField().get(0));
+        finishTestAndReset();
+      }
+    });
+  }
+
+  /**
    * Test that we can commit child objects.
    */
   public void testCascadingCommit() {
@@ -222,11 +344,6 @@
     });
   }
 
-  public void testChangedNothing() {
-    SimpleFooRequest context = simpleFooRequest();
-    assertFalse(context.isChanged());
-  }
-
   public void testChangedCreate() {
     SimpleFooRequest context = simpleFooRequest();
 
@@ -277,6 +394,11 @@
         });
   }
 
+  public void testChangedNothing() {
+    SimpleFooRequest context = simpleFooRequest();
+    assertFalse(context.isChanged());
+  }
+
   public void testClassToken() {
     String token = req.getHistoryToken(SimpleFooProxy.class);
     assertEquals(SimpleFooProxy.class, req.getProxyClass(token));
@@ -285,6 +407,21 @@
     assertEquals(SimpleFooProxy.class, foo.stableId().getProxyClass());
   }
 
+  public void testCollectionSubProperties() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().getSimpleFooWithSubPropertyCollection().with(
+        "selfOneToManyField", "selfOneToManyField.fooField").fire(
+        new Receiver<SimpleFooProxy>() {
+          @Override
+          public void onSuccess(SimpleFooProxy response) {
+            assertEquals(
+                "I'm here",
+                response.getSelfOneToManyField().get(0).getFooField().getUserName());
+            finishTestAndReset();
+          }
+        });
+  }
+
   public void testDummyCreate() {
     delayTestFinish(DELAY_TEST_FINISH);
 
@@ -361,48 +498,6 @@
     });
   }
 
-  public void disabled_testEchoSimpleFutures() {
-    // tests if futureIds can be echoed back.
-    delayTestFinish(DELAY_TEST_FINISH);
-    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
-    EntityProxyChange.registerForProxyType(req.getEventBus(),
-        SimpleFooProxy.class, handler);
-    SimpleFooRequest context = req.simpleFooRequest();
-    final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
-    context.echo(simpleFoo).fire(new Receiver<SimpleFooProxy>() {
-      @Override
-      public void onSuccess(SimpleFooProxy response) {
-        assertEquals(0, handler.totalEventCount);
-        checkStableIdEquals(simpleFoo, response);
-        finishTestAndReset();
-      }
-    });
-  }
-
-  public void disabled_testEchoComplexFutures() {
-    // relate futures on the server. Check if the relationship is still present
-    // on the client.
-    delayTestFinish(DELAY_TEST_FINISH);
-    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
-    EntityProxyChange.registerForProxyType(req.getEventBus(),
-        SimpleFooProxy.class, handler);
-    SimpleFooRequest context = req.simpleFooRequest();
-    final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
-    final SimpleBarProxy simpleBar = context.create(SimpleBarProxy.class);
-    context.echoComplex(simpleFoo, simpleBar).fire(
-        new Receiver<SimpleFooProxy>() {
-          @Override
-          public void onSuccess(SimpleFooProxy response) {
-            assertEquals(0, handler.totalEventCount);
-            checkStableIdEquals(simpleFoo, response);
-            SimpleBarProxy responseBar = response.getBarField();
-            assertNotNull(responseBar);
-            checkStableIdEquals(simpleBar, responseBar);
-            finishTestAndReset();
-          }
-        });
-  }
-
   /**
    * Tests behaviors relating to editing an object with one context and then
    * using with another.
@@ -503,6 +598,67 @@
     });
   }
 
+  public void testFindFindEdit() {
+    delayTestFinish(5000);
+
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
+
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
+
+          @Override
+          public void onSuccess(SimpleFooProxy newFoo) {
+            assertEquals(1, handler.updateEventCount);
+            assertEquals(1, handler.totalEventCount);
+
+            req.simpleFooRequest().findSimpleFooById(999L).fire(
+                new Receiver<SimpleFooProxy>() {
+
+                  @Override
+                  public void onSuccess(SimpleFooProxy newFoo) {
+                    // no events are fired second time.
+                    assertEquals(1, handler.updateEventCount);
+                    assertEquals(1, handler.totalEventCount);
+                    SimpleFooRequest context = req.simpleFooRequest();
+                    final Request<Void> mutateRequest = context.persist().using(
+                        newFoo);
+                    newFoo = context.edit(newFoo);
+                    newFoo.setUserName("Ray");
+                    mutateRequest.fire(new Receiver<Void>() {
+                      @Override
+                      public void onSuccess(Void response) {
+                        // events fired on updates.
+                        assertEquals(2, handler.updateEventCount);
+                        assertEquals(2, handler.totalEventCount);
+
+                        finishTestAndReset();
+                      }
+                    });
+                  }
+                });
+          }
+        });
+  }
+
+  public void testForwardReferenceDecode() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().getTripletReference().with(
+        "selfOneToManyField.selfOneToManyField.fooField").fire(
+        new Receiver<SimpleFooProxy>() {
+          public void onSuccess(SimpleFooProxy response) {
+            assertNotNull(response.getSelfOneToManyField().get(0));
+            assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField());
+            assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField().get(
+                0));
+            assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField().get(
+                0).getFooField());
+            finishTestAndReset();
+          }
+        });
+  }
+
   public void testGetEventBus() {
     assertEquals(eventBus, req.getEventBus());
   }
@@ -582,6 +738,87 @@
     });
   }
 
+  /*
+   * tests that (a) any method can have a side effect that is handled correctly.
+   * (b) instance methods are handled correctly and (c) a request cannot be
+   * reused after a successful response is received. (Yet?)
+   */
+  public void testMethodWithSideEffects() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
+
+    simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
+
+          @Override
+          public void onSuccess(SimpleFooProxy newFoo) {
+            assertEquals(1, handler.updateEventCount);
+            assertEquals(1, handler.totalEventCount);
+            SimpleFooRequest context = simpleFooRequest();
+            final Request<Long> mutateRequest = context.countSimpleFooWithUserNameSideEffect().using(
+                newFoo);
+            newFoo = context.edit(newFoo);
+            newFoo.setUserName("Ray");
+            mutateRequest.fire(new Receiver<Long>() {
+              @Override
+              public void onSuccess(Long response) {
+                assertCannotFire(mutateRequest);
+                assertEquals(new Long(2L), response);
+                assertEquals(2, handler.updateEventCount);
+                assertEquals(2, handler.totalEventCount);
+
+                // confirm that the instance method did have the desired
+                // sideEffect.
+                simpleFooRequest().findSimpleFooById(999L).fire(
+                    new Receiver<SimpleFooProxy>() {
+                      @Override
+                      public void onSuccess(SimpleFooProxy finalFoo) {
+                        assertEquals("Ray", finalFoo.getUserName());
+                        assertEquals(2, handler.updateEventCount);
+                        assertEquals(2, handler.totalEventCount);
+                        finishTestAndReset();
+                      }
+                    });
+              }
+
+            });
+
+            try {
+              newFoo.setUserName("Barney");
+              fail();
+            } catch (IllegalStateException e) {
+              /* pass, cannot change a request that is in flight */
+            }
+          }
+        });
+  }
+
+  public void testMultipleEdits() {
+    RequestContext c1 = req.simpleFooRequest();
+    SimpleFooProxy proxy = c1.create(SimpleFooProxy.class);
+    // Re-editing is idempotent
+    assertSame(proxy, c1.edit(c1.edit(proxy)));
+
+    // Should not allow "crossing the steams"
+    RequestContext c2 = req.simpleFooRequest();
+    try {
+      c2.edit(proxy);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullEntityProxyResult() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
+  }
+
   /**
    * Test that a null value can be sent in a request.
    */
@@ -597,6 +834,14 @@
   }
 
   /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullListResult() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().returnNullList().fire(new NullReceiver());
+  }
+
+  /**
    * Test that a null value can be sent in a request.
    */
   public void testNullSimpleFooRequest() {
@@ -649,6 +894,14 @@
   }
 
   /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullStringResult() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().returnNullString().fire(new NullReceiver());
+  }
+
+  /**
    * Test that a null value can be sent within a list of entities.
    */
   public void testNullValueInEntityListRequest() {
@@ -679,7 +932,7 @@
    */
   public void testNullValueInIntegerListRequest() {
     delayTestFinish(DELAY_TEST_FINISH);
-    List<Integer> list = Arrays.asList(new Integer[] {1, 2, null});
+    List<Integer> list = Arrays.asList(new Integer[]{1, 2, null});
     final Request<Void> fooReq = req.simpleFooRequest().receiveNullValueInIntegerList(
         list);
     fooReq.fire(new Receiver<Void>() {
@@ -695,7 +948,7 @@
    */
   public void testNullValueInStringListRequest() {
     delayTestFinish(DELAY_TEST_FINISH);
-    List<String> list = Arrays.asList(new String[] {"nonnull", "null", null});
+    List<String> list = Arrays.asList(new String[]{"nonnull", "null", null});
     final Request<Void> fooReq = req.simpleFooRequest().receiveNullValueInStringList(
         list);
     fooReq.fire(new Receiver<Void>() {
@@ -706,164 +959,6 @@
     });
   }
 
-  /**
-   * Ensures that a service method can respond with a null value.
-   */
-  public void testNullListResult() {
-    delayTestFinish(DELAY_TEST_FINISH);
-    simpleFooRequest().returnNullList().fire(new NullReceiver());
-  }
-
-  public void testMultipleEdits() {
-    RequestContext c1 = req.simpleFooRequest();
-    SimpleFooProxy proxy = c1.create(SimpleFooProxy.class);
-    // Re-editing is idempotent
-    assertSame(proxy, c1.edit(c1.edit(proxy)));
-
-    // Should not allow "crossing the steams"
-    RequestContext c2 = req.simpleFooRequest();
-    try {
-      c2.edit(proxy);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-  }
-
-  /**
-   * Ensures that a service method can respond with a null value.
-   */
-  public void testNullEntityProxyResult() {
-    delayTestFinish(DELAY_TEST_FINISH);
-    simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
-  }
-
-  /**
-   * Ensures that a service method can respond with a null value.
-   */
-  public void testNullStringResult() {
-    delayTestFinish(DELAY_TEST_FINISH);
-    simpleFooRequest().returnNullString().fire(new NullReceiver());
-  }
-
-  /*
-   * tests that (a) any method can have a side effect that is handled correctly.
-   * (b) instance methods are handled correctly and (c) a request cannot be
-   * reused after a successful response is received. (Yet?)
-   */
-  public void testMethodWithSideEffects() {
-    delayTestFinish(DELAY_TEST_FINISH);
-
-    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
-    EntityProxyChange.registerForProxyType(req.getEventBus(),
-        SimpleFooProxy.class, handler);
-
-    simpleFooRequest().findSimpleFooById(999L).fire(
-        new Receiver<SimpleFooProxy>() {
-
-          @Override
-          public void onSuccess(SimpleFooProxy newFoo) {
-            assertEquals(1, handler.updateEventCount);
-            assertEquals(1, handler.totalEventCount);
-            SimpleFooRequest context = simpleFooRequest();
-            final Request<Long> mutateRequest = context.countSimpleFooWithUserNameSideEffect().using(
-                newFoo);
-            newFoo = context.edit(newFoo);
-            newFoo.setUserName("Ray");
-            mutateRequest.fire(new Receiver<Long>() {
-              @Override
-              public void onSuccess(Long response) {
-                assertCannotFire(mutateRequest);
-                assertEquals(new Long(2L), response);
-                assertEquals(2, handler.updateEventCount);
-                assertEquals(2, handler.totalEventCount);
-
-                // confirm that the instance method did have the desired
-                // sideEffect.
-                simpleFooRequest().findSimpleFooById(999L).fire(
-                    new Receiver<SimpleFooProxy>() {
-                      @Override
-                      public void onSuccess(SimpleFooProxy finalFoo) {
-                        assertEquals("Ray", finalFoo.getUserName());
-                        assertEquals(3, handler.updateEventCount);
-                        assertEquals(3, handler.totalEventCount);
-                        finishTestAndReset();
-                      }
-                    });
-              }
-
-            });
-
-            try {
-              newFoo.setUserName("Barney");
-              fail();
-            } catch (IllegalStateException e) {
-              /* pass, cannot change a request that is in flight */
-            }
-          }
-        });
-  }
-
-  /**
-   * Test that removing a parent entity and implicitly removing the child sends
-   * an event to the client that the child was removed.
-   * 
-   * TODO(rjrjr): Should cascading deletes be detected?
-   */
-  public void disableTestMethodWithSideEffectDeleteChild() {
-    delayTestFinish(DELAY_TEST_FINISH);
-
-    // Persist bar.
-    SimpleBarRequest context = req.simpleBarRequest();
-    final SimpleBarProxy bar = context.create(SimpleBarProxy.class);
-    context.persistAndReturnSelf().using(bar).fire(
-        new Receiver<SimpleBarProxy>() {
-          @Override
-          public void onSuccess(SimpleBarProxy persistentBar) {
-            // Persist foo with bar as a child.
-            SimpleFooRequest context = req.simpleFooRequest();
-            SimpleFooProxy foo = context.create(SimpleFooProxy.class);
-            final Request<SimpleFooProxy> persistRequest = context.persistAndReturnSelf().using(
-                foo);
-            foo = context.edit(foo);
-            foo.setUserName("John");
-            foo.setBarField(bar);
-            persistRequest.fire(new Receiver<SimpleFooProxy>() {
-              @Override
-              public void onSuccess(SimpleFooProxy persistentFoo) {
-                // Handle changes to SimpleFooProxy.
-                final SimpleFooEventHandler<SimpleFooProxy> fooHandler = new SimpleFooEventHandler<SimpleFooProxy>();
-                EntityProxyChange.registerForProxyType(req.getEventBus(),
-                    SimpleFooProxy.class, fooHandler);
-
-                // Handle changes to SimpleBarProxy.
-                final SimpleFooEventHandler<SimpleBarProxy> barHandler = new SimpleFooEventHandler<SimpleBarProxy>();
-                EntityProxyChange.registerForProxyType(req.getEventBus(),
-                    SimpleBarProxy.class, barHandler);
-
-                // Delete bar.
-                SimpleFooRequest context = req.simpleFooRequest();
-                final Request<Void> deleteRequest = context.deleteBar().using(
-                    persistentFoo);
-                SimpleFooProxy editable = context.edit(persistentFoo);
-                editable.setBarField(bar);
-                deleteRequest.fire(new Receiver<Void>() {
-                  @Override
-                  public void onSuccess(Void response) {
-                    assertEquals(1, fooHandler.updateEventCount); // set bar to
-                    // null
-                    assertEquals(1, fooHandler.totalEventCount);
-
-                    assertEquals(1, barHandler.deleteEventCount); // deleted bar
-                    assertEquals(1, barHandler.totalEventCount);
-                    finishTestAndReset();
-                  }
-                });
-              }
-            });
-          }
-        });
-  }
-
   public void testPersistAllValueTypes() {
     delayTestFinish(DELAY_TEST_FINISH);
 
@@ -871,8 +966,8 @@
     SimpleFooProxy f = r.create(SimpleFooProxy.class);
 
     f.setUserName("user name");
-    f.setByteField((byte)100);
-    f.setShortField((short)12345);
+    f.setByteField((byte) 100);
+    f.setShortField((short) 12345);
     f.setFloatField(1234.56f);
     f.setDoubleField(1.2345);
     f.setLongField(1234L);
@@ -884,8 +979,8 @@
       @Override
       public void onSuccess(SimpleFooProxy f) {
         assertEquals("user name", f.getUserName());
-        assertEquals(Byte.valueOf((byte)100), f.getByteField());
-        assertEquals(Short.valueOf((short)12345), f.getShortField());
+        assertEquals(Byte.valueOf((byte) 100), f.getByteField());
+        assertEquals(Short.valueOf((short) 12345), f.getShortField());
         assertEquals(Float.valueOf(1234.56f), f.getFloatField());
         assertEquals(Double.valueOf(1.2345), f.getDoubleField());
         assertEquals(Long.valueOf(1234L), f.getLongField());
@@ -922,35 +1017,35 @@
                     fooProxy.setBarField(barProxy);
                     fooProxy.setUserName("Hello");
                     fooProxy.setByteField((byte) 55);
-                    context.persistAndReturnSelf().using(fooProxy).fire(
-                        new Receiver<SimpleFooProxy>() {
-                          @Override
-                          public void onSuccess(SimpleFooProxy received) {
-                            // Check that Foo points to Bar
-                            assertNotNull(received.getBarField());
-                            assertEquals(barProxy.stableId(),
-                                received.getBarField().stableId());
-                            assertEquals("Hello", received.getUserName());
-                            assertTrue(55 == received.getByteField());
+                    context.persistAndReturnSelf().using(fooProxy).with(
+                        "barField").fire(new Receiver<SimpleFooProxy>() {
+                      @Override
+                      public void onSuccess(SimpleFooProxy received) {
+                        // Check that Foo points to Bar
+                        assertNotNull(received.getBarField());
+                        assertEquals(barProxy.stableId(),
+                            received.getBarField().stableId());
+                        assertEquals("Hello", received.getUserName());
+                        assertTrue(55 == received.getByteField());
 
-                            // Unset the association
-                            SimpleFooRequest context = simpleFooRequest();
-                            received = context.edit(received);
-                            received.setBarField(null);
-                            received.setUserName(null);
-                            received.setByteField(null);
-                            context.persistAndReturnSelf().using(received).fire(
-                                new Receiver<SimpleFooProxy>() {
-                                  @Override
-                                  public void onSuccess(SimpleFooProxy response) {
-                                    assertNull(response.getBarField());
-                                    assertNull(response.getUserName());
-                                    assertNull(response.getByteField());
-                                    finishTestAndReset();
-                                  }
-                                });
-                          }
-                        });
+                        // Unset the association
+                        SimpleFooRequest context = simpleFooRequest();
+                        received = context.edit(received);
+                        received.setBarField(null);
+                        received.setUserName(null);
+                        received.setByteField(null);
+                        context.persistAndReturnSelf().using(received).fire(
+                            new Receiver<SimpleFooProxy>() {
+                              @Override
+                              public void onSuccess(SimpleFooProxy response) {
+                                assertNull(response.getBarField());
+                                assertNull(response.getUserName());
+                                assertNull(response.getByteField());
+                                finishTestAndReset();
+                              }
+                            });
+                      }
+                    });
                   }
                 });
           }
@@ -1010,6 +1105,30 @@
     });
   }
 
+  /**
+   * Ensure that a relationship can be set up between two newly-created objects.
+   */
+  public void testPersistFutureToFuture() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    SimpleFooRequest context = simpleFooRequest();
+    SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
+    final SimpleBarProxy newBar = context.create(SimpleBarProxy.class);
+
+    Request<SimpleFooProxy> fooReq = context.persistAndReturnSelf().using(
+        newFoo).with("barField");
+    newFoo = context.edit(newFoo);
+    newFoo.setBarField(newBar);
+
+    fooReq.fire(new Receiver<SimpleFooProxy>() {
+      @Override
+      public void onSuccess(SimpleFooProxy response) {
+        assertNotNull(response.getBarField());
+        assertEquals(newBar.stableId(), response.getBarField().stableId());
+        finishTestAndReset();
+      }
+    });
+  }
+
   /*
    * Find Entity2 Create Entity, Persist Entity Relate Entity2 to Entity Persist
    * Entity
@@ -1048,30 +1167,6 @@
         });
   }
 
-  /**
-   * Ensure that a relationship can be set up between two newly-created objects.
-   */
-  public void testPersistFutureToFuture() {
-    delayTestFinish(DELAY_TEST_FINISH);
-    SimpleFooRequest context = simpleFooRequest();
-    SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
-    final SimpleBarProxy newBar = context.create(SimpleBarProxy.class);
-
-    Request<SimpleFooProxy> fooReq = context.persistAndReturnSelf().using(
-        newFoo).with("barField");
-    newFoo = context.edit(newFoo);
-    newFoo.setBarField(newBar);
-
-    fooReq.fire(new Receiver<SimpleFooProxy>() {
-      @Override
-      public void onSuccess(SimpleFooProxy response) {
-        assertNotNull(response.getBarField());
-        assertEquals(newBar.stableId(), response.getBarField().stableId());
-        finishTestAndReset();
-      }
-    });
-  }
-
   /*
    * Create Entity, Persist Entity Create Entity2, Perist Entity2 relate Entity2
    * to Entity Persist
@@ -1933,14 +2028,14 @@
     });
   }
 
-  protected SimpleFooRequest simpleFooRequest() {
-    return req.simpleFooRequest();
-  }
-
   protected SimpleBarRequest simpleBarRequest() {
     return req.simpleBarRequest();
   }
 
+  protected SimpleFooRequest simpleFooRequest() {
+    return req.simpleFooRequest();
+  }
+
   private void assertCannotFire(final Request<Long> mutateRequest) {
     try {
       mutateRequest.fire(new Receiver<Long>() {
diff --git a/user/test/com/google/gwt/requestfactory/client/EditorTest.java b/user/test/com/google/gwt/requestfactory/client/ui/EditorTest.java
similarity index 97%
rename from user/test/com/google/gwt/requestfactory/client/EditorTest.java
rename to user/test/com/google/gwt/requestfactory/client/ui/EditorTest.java
index 2db02d6..6b1cc48 100644
--- a/user/test/com/google/gwt/requestfactory/client/EditorTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/ui/EditorTest.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.requestfactory.client;
+package com.google.gwt.requestfactory.client.ui;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
@@ -24,6 +24,8 @@
 import com.google.gwt.editor.client.HasEditorDelegate;
 import com.google.gwt.editor.client.HasEditorErrors;
 import com.google.gwt.editor.client.adapters.SimpleEditor;
+import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
+import com.google.gwt.requestfactory.client.RequestFactoryTestBase;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.shared.Request;
 import com.google.gwt.requestfactory.shared.SimpleBarProxy;
diff --git a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
new file mode 100644
index 0000000..42a821b
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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.requestfactory.rebind.model;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationStateBuilder;
+import com.google.gwt.dev.javac.impl.JavaResourceBase;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.UnitTestTreeLogger;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.requestfactory.server.TestContextImpl;
+import com.google.gwt.requestfactory.server.TestContextNoIdImpl;
+import com.google.gwt.requestfactory.server.TestContextNoVersionImpl;
+import com.google.gwt.requestfactory.shared.EntityProxy;
+import com.google.gwt.requestfactory.shared.InstanceRequest;
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.Request;
+import com.google.gwt.requestfactory.shared.RequestContext;
+import com.google.gwt.requestfactory.shared.RequestFactory;
+import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.impl.Property;
+
+import junit.framework.TestCase;
+
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * Test case for {@link com.google.gwt.requestfactory.rebind.model.RequestFactoryModel}
+ * that uses mock CompilationStates.
+ */
+public class RequestFactoryModelTest extends TestCase {
+
+  /**
+   * Constructs an empty interface representation of a type.
+   */
+  private static class EmptyMockJavaResource extends MockJavaResource {
+
+    private final StringBuilder code = new StringBuilder();
+
+    public EmptyMockJavaResource(Class<?> clazz) {
+      super(clazz.getName());
+
+      code.append("package ").append(clazz.getPackage().getName())
+          .append(";\n");
+      code.append("public interface ").append(clazz.getSimpleName());
+
+      int numParams = clazz.getTypeParameters().length;
+      if (numParams != 0) {
+        code.append("<");
+        for (int i = 0; i < numParams; i++) {
+          if (i != 0) {
+            code.append(",");
+          }
+          code.append("T").append(i);
+        }
+        code.append(">");
+      }
+
+      code.append("{}\n");
+    }
+
+    @Override
+    protected CharSequence getContent() {
+      return code;
+    }
+  }
+
+  /**
+   * Loads the actual source of a type. This should be used only for types
+   * directly tested by this test. Note that use of this class requires your
+   * source files to be on your classpath.
+   */
+  private static class RealJavaResource extends MockJavaResource {
+
+    public RealJavaResource(Class<?> clazz) {
+      super(clazz.getName());
+    }
+
+    @Override
+    protected CharSequence getContent() {
+      String resourceName = getTypeName().replace('.', '/') + ".java";
+      InputStream stream = Thread.currentThread().getContextClassLoader()
+          .getResourceAsStream(resourceName);
+      return Util.readStreamAsString(stream);
+    }
+  }
+
+  private static TreeLogger createCompileLogger() {
+    PrintWriterTreeLogger logger = new PrintWriterTreeLogger(
+        new PrintWriter(System.err, true));
+    logger.setMaxDetail(TreeLogger.ERROR);
+    return logger;
+  }
+
+  private TreeLogger logger;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    logger = createCompileLogger();
+  }
+
+  public void testBadCollectionType() {
+    testModelWithMethodDecl("Request<SortedSet<Integer>> badReturnType();",
+        "Requests that return collections may be declared with java.util.List or java.util.Set only");
+  }
+
+  public void testBadCollectionTypeNotParameterized() {
+    testModelWithMethodDecl("Request<SortedSet> badReturnType();",
+        "Requests that return collections of List or Set must be parameterized");
+  }
+
+  public void testBadReturnType() {
+    testModelWithMethodDecl("Request<Iterable> badReturnType();",
+        "Invalid Request parameterization java.lang.Iterable");
+  }
+
+  public void testMismatchedArityInstance() {
+    testModelWithMethodDecl(
+        "InstanceRequest<TestProxy, String> mismatchedArityInstance(TestProxy p, int x);",
+        "Parameter 0 of method TestContext.mismatchedArityInstance does not match method com.google.gwt.requestfactory.server.TestContextImpl.mismatchedArityInstance");
+  }
+
+  public void testMismatchedArityStatic() {
+    testModelWithMethodDecl("Request<String> mismatchedArityStatic(int x);",
+        "Method TestContext.mismatchedArityStatic parameters do not match same method on com.google.gwt.requestfactory.server.TestContextImpl");
+  }
+
+  public void testMismatchedModifierNonStatic() {
+    testModelWithMethodDecl(
+        "InstanceRequest<TestProxy, String> mismatchedNonStatic();",
+        "Method TestContext.mismatchedNonStatic is an instance method, while the corresponding method on com.google.gwt.requestfactory.server.TestContextImpl is static");
+  }
+
+  public void testMismatchedModifierStatic() {
+    testModelWithMethodDecl("Request<String> mismatchedStatic();",
+        "Method TestContext.mismatchedStatic is a static method, while the corresponding method on com.google.gwt.requestfactory.server.TestContextImpl is not");
+  }
+
+  public void testMismatchedParamType() {
+    testModelWithMethodDecl("Request<String> mismatchedParamType(Integer x);",
+        "Parameter 0 of method TestContext.mismatchedParamType does not match method com.google.gwt.requestfactory.server.TestContextImpl.mismatchedParamType");
+  }
+
+  public void testMismatchedReturnType() {
+    testModelWithMethodDecl("Request<String> mismatchedReturnType();",
+        "Return type of method TestContext.mismatchedReturnType does not match method com.google.gwt.requestfactory.server.TestContextImpl.mismatchedReturnType");
+  }
+
+  public void testMissingId() {
+    testModelWithMethodDeclArgs("Request<TestProxy> okMethodProxy();",
+        TestContextNoIdImpl.class.getName(),
+        TestContextNoIdImpl.class.getName(),
+        "The class com.google.gwt.requestfactory.server.TestContextNoIdImpl is missing method getId()");
+  }
+
+  public void testMissingMethod() {
+    testModelWithMethodDecl("Request<String> missingMethod();",
+        "Method t.TestContext.missingMethod has no corresponding public method on"
+            + " com.google.gwt.requestfactory.server.TestContextImpl");
+  }
+
+  public void testMissingProxyFor() {
+    testModelWithMethodDeclArgs("Request<TestProxy> okMethodProxy();",
+        TestContextImpl.class.getName(), null,
+        "The t.TestProxy type does not have a @ProxyFor annotation");
+  }
+
+  public void testMissingService() {
+    testModelWithMethodDeclArgs("Request<String> okMethod();", null,
+        TestContextImpl.class.getName(),
+        "RequestContext subtype t.TestContext is missing a @Service annotation");
+  }
+
+  public void testMissingVersion() {
+    testModelWithMethodDeclArgs("Request<TestProxy> okMethodProxy();",
+        TestContextNoVersionImpl.class.getName(),
+        TestContextNoVersionImpl.class.getName(),
+        "The class com.google.gwt.requestfactory.server.TestContextNoVersionImpl is missing method getVersion()");
+  }
+
+  public void testModelWithMethodDecl(final String clientMethodDecls,
+      String... expected) {
+    testModelWithMethodDeclArgs(clientMethodDecls,
+        TestContextImpl.class.getName(), TestContextImpl.class.getName(),
+        expected);
+  }
+
+  public void testModelWithMethodDeclArgs(final String clientMethodDecls,
+      final String serviceClass, String proxyClass, String... expected) {
+    Set<Resource> javaResources = getJavaResources(proxyClass);
+    javaResources.add(new MockJavaResource("t.TestRequestFactory") {
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package t;\n");
+        code.append("import " + RequestFactory.class.getName() + ";\n");
+        code.append("interface TestRequestFactory extends RequestFactory {\n");
+        code.append("TestContext testContext();");
+        code.append("}");
+        return code;
+      }
+    });
+    javaResources.add(new MockJavaResource("t.TestContext") {
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package t;\n");
+        code.append("import " + Request.class.getName() + ";\n");
+        code.append("import " + InstanceRequest.class.getName() + ";\n");
+
+        code.append("import " + RequestContext.class.getName() + ";\n");
+        code.append("import " + SortedSet.class.getName() + ";\n");
+        code.append("import " + List.class.getName() + ";\n");
+        code.append("import " + Set.class.getName() + ";\n");
+        code.append("import " + Service.class.getName() + ";\n");
+        code.append("import " + TestContextImpl.class.getName() + ";\n");
+
+        if (serviceClass != null) {
+          code.append("@Service(" + serviceClass + ".class)");
+        }
+        code.append("interface TestContext extends RequestContext {\n");
+        code.append(clientMethodDecls);
+        code.append("}");
+        return code;
+      }
+    });
+
+    CompilationState state = CompilationStateBuilder
+        .buildFrom(logger, javaResources);
+
+    UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
+    builder.setLowestLogLevel(TreeLogger.ERROR);
+    for (String expectedMsg : expected) {
+      builder.expectError(expectedMsg, null);
+    }
+    builder.expectError(RequestFactoryModel.poisonedMessage(), null);
+    UnitTestTreeLogger testLogger = builder.createLogger();
+    try {
+      new RequestFactoryModel(testLogger,
+          state.getTypeOracle().findType("t.TestRequestFactory"));
+      fail("Should have complained");
+    } catch (UnableToCompleteException e) {
+    }
+    testLogger.assertCorrectLogEntries();
+  }
+
+  public void testOverloadedMethod() {
+    testModelWithMethodDecl("Request<String> overloadedMethod();",
+        "Method t.TestContext.overloadedMethod is overloaded on com.google.gwt.requestfactory.server.TestContextImpl");
+  }
+
+  private Set<Resource> getJavaResources(final String proxyClass) {
+    MockJavaResource[] javaFiles = {new MockJavaResource("t.AddressProxy") {
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package t;\n");
+        code.append("import " + ProxyFor.class.getName() + ";\n");
+        code.append("import " + EntityProxy.class.getName() + ";\n");
+        if (proxyClass != null) {
+          code.append("@ProxyFor(" + proxyClass + ".class)");
+        }
+        code.append("interface TestProxy extends EntityProxy {\n");
+        code.append("}");
+        return code;
+      }
+    }, new MockJavaResource("java.util.List") {
+      // Tests a Driver interface that extends more than RFED
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package java.util;\n");
+        code.append("public interface List<T> extends Collection<T> {\n");
+        code.append("}");
+        return code;
+      }
+    }, new MockJavaResource("java.util.Set") {
+      // Tests a Driver interface that extends more than RFED
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package java.util;\n");
+        code.append("public interface Set<T> extends Collection<T> {\n");
+        code.append("}");
+        return code;
+      }
+    }, new MockJavaResource("java.util.SortedSet") {
+      // Tests a Driver interface that extends more than RFED
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package java.util;\n");
+        code.append("public interface SortedSet<T> extends Set<T> {\n");
+        code.append("}");
+        return code;
+      }
+    }};
+
+    Set<Resource> toReturn = new HashSet<Resource>(Arrays.asList(javaFiles));
+
+    toReturn.addAll(Arrays.asList(
+        new Resource[]{new EmptyMockJavaResource(Iterable.class),
+            new EmptyMockJavaResource(Property.class),
+            new EmptyMockJavaResource(EntityProxy.class),
+            new EmptyMockJavaResource(InstanceRequest.class),
+            new EmptyMockJavaResource(RequestFactory.class),
+            new EmptyMockJavaResource(Receiver.class),
+
+            new RealJavaResource(Request.class),
+            new RealJavaResource(Service.class),
+            new RealJavaResource(ProxyFor.class),
+            new EmptyMockJavaResource(RequestContext.class),}));
+    toReturn.addAll(Arrays.asList(JavaResourceBase.getStandardResources()));
+    return toReturn;
+  }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
index 23a0f94..919f897 100644
--- a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
+++ b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
@@ -111,6 +111,7 @@
     // nulls becomes JSON Null. Needed because JSONObject stringify treats 'null'
     // as a reason to not emit the key in the stringified object
     assertEquals(JSONObject.NULL, requestProcessor.encodePropertyValue(null));
+    assertEquals(new Double(1.0), requestProcessor.encodePropertyValue(new Integer(1)));
   }
 
   public void testEndToEnd() throws Exception {
@@ -134,8 +135,9 @@
     JSONArray updateArray = result.getJSONObject("sideEffects").getJSONArray(
         "UPDATE");
     assertEquals(1, updateArray.length());
-    assertEquals(1, updateArray.getJSONObject(0).length());
+    assertEquals(2, updateArray.getJSONObject(0).length());
     assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_ID_PROPERTY));
+    assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_VERSION_PROPERTY));
     assertFalse(updateArray.getJSONObject(0).has("violations"));
     assertEquals(45, (int) fooResult.getIntId());
     assertEquals("JSC", fooResult.getUserName());
@@ -146,26 +148,102 @@
     assertEquals(false, (boolean) fooResult.getBoolField());
   }
 
+  private String createNoChangeRequestAndGetServerVersion(JSONObject foo) throws Exception {
+    // change the value on the server behind the back
+    SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
+    fooResult.setUserName("JSC");
+    fooResult.setIntId(45);
+    String savedVersion = requestProcessor.encodePropertyValue(fooResult.getVersion() + 1).toString();
+    fooResult.setVersion(fooResult.getVersion() + 1);
+    fooResult.isChanged = false;
+
+    // modify fields and sync -- there should be no change on the server.
+    foo.put("intId", 45);
+    foo.put("userName", "JSC");
+    return savedVersion;
+  }
+
   public void testEndToEndSmartDiff_NoChange() throws Exception {
     com.google.gwt.requestfactory.server.SimpleFoo.reset();
     // fetch object
     JSONObject foo = fetchVerifyAndGetInitialObject();
 
-    // change the value on the server behind the back
-    SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
-    fooResult.setUserName("JSC");
-    fooResult.setIntId(45);
+    String savedVersion = createNoChangeRequestAndGetServerVersion(foo);
+    JSONObject result = getResultFromServer(foo);
 
-    // modify fields and sync -- there should be no change on the server.
-    foo.put("intId", 45);
-    foo.put("userName", "JSC");
+    // check modified fields and no violations
+    assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
+    JSONArray updateArray = result.getJSONObject("sideEffects").getJSONArray(
+        "UPDATE");
+    // verify that the version number is unchanged.
+    assertEquals(1, updateArray.length());
+    assertEquals(2, updateArray.getJSONObject(0).length());
+    assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_ID_PROPERTY));
+    assertTrue(updateArray.getJSONObject(0).has(
+        Constants.ENCODED_VERSION_PROPERTY));
+    assertEquals(savedVersion,
+        updateArray.getJSONObject(0).getString(
+            Constants.ENCODED_VERSION_PROPERTY));
+    // verify that the server values are unchanged.
+    SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
+    assertEquals(45, (int) fooResult.getIntId());
+    assertEquals("JSC", fooResult.getUserName());
+    assertEquals(savedVersion,
+        requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
+  }
+
+  /*
+   * This test differs from testEndToEndSmartDiff_NoChange in that the version
+   * numbers are not sent. As a result, the server does not send an UPDATE
+   * sideEffect in its response.
+   */
+  public void testEndToEndSmartDiff_NoChange_NoVersion() throws Exception {
+    com.google.gwt.requestfactory.server.SimpleFoo.reset();
+    // fetch object
+    JSONObject foo = fetchVerifyAndGetInitialObject();
+
+    String savedVersion = createNoChangeRequestAndGetServerVersion(foo);
+    // remove version number from the request.
+    foo.remove(Constants.ENCODED_VERSION_PROPERTY);
     JSONObject result = getResultFromServer(foo);
 
     // check modified fields and no violations
     assertFalse(result.getJSONObject("sideEffects").has("UPDATE"));
-    fooResult = SimpleFoo.findSimpleFooById(999L);
+
+    // verify that the server values are unchanged.
+    SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
     assertEquals(45, (int) fooResult.getIntId());
     assertEquals("JSC", fooResult.getUserName());
+    assertEquals(savedVersion,
+        requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
+  }
+
+  /*
+   * This test differs from testEndToEndSmartDiff_NoChange in that the property
+   * that is changed here does not cause a version increment. As a result, no
+   * UPDATE is sent back.
+   */
+  public void testEndToEndSmartDiff_NoVersionChange() throws Exception {
+    com.google.gwt.requestfactory.server.SimpleFoo.reset();
+    // fetch object
+    JSONObject foo = fetchVerifyAndGetInitialObject();
+    // change the value on the server behind the back
+    SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
+    fooResult.setLongField(45L);
+    String savedVersion = requestProcessor.encodePropertyValue(fooResult.getVersion()).toString();
+    
+    // modify fields and sync -- there should be no change on the server.
+    foo.put("longField", 45L);
+    JSONObject result = getResultFromServer(foo);
+
+    // check modified fields and no violations
+    assertFalse(result.getJSONObject("sideEffects").has("UPDATE"));
+
+    // verify that the server values are unchanged.
+    fooResult = SimpleFoo.findSimpleFooById(999L);
+    assertEquals(45L, (long) fooResult.getLongField());
+    assertEquals(savedVersion,
+        requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
   }
 
   public void testEndToEndSmartDiff_SomeChangeWithNull() throws Exception {
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
index fd47a98..80495e9 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
@@ -80,7 +80,7 @@
       Map<String, SimpleBar> value = (Map<String, SimpleBar>) req.getSession().getAttribute(
           SimpleBar.class.getCanonicalName());
       if (value == null) {
-        value = reset();
+        value = resetImpl();
       }
       return value;
     }
@@ -95,7 +95,11 @@
     return toReturn;
   }
 
-  public static synchronized Map<String, SimpleBar> reset() {
+  public static void reset() {
+    resetImpl();
+  }
+
+  public static synchronized Map<String, SimpleBar> resetImpl() {
     Map<String, SimpleBar> instance = new HashMap<String, SimpleBar>();
     // fixtures
     SimpleBar s1 = new SimpleBar();
@@ -157,6 +161,7 @@
       isNew = false;
       get().put(getId(), this);
     }
+    version++;
   }
 
   public SimpleBar persistAndReturnSelf() {
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index 6e2b989..bef8b4a 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -21,6 +21,7 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -59,6 +60,16 @@
     return simpleFoo;
   }
 
+  public static SimpleFoo fetchDoubleReference() {
+    SimpleFoo foo = new SimpleFoo();
+    SimpleFoo foo2 = new SimpleFoo();
+    foo.setFooField(foo2);
+    foo.setSelfOneToManyField(Arrays.asList(foo2));
+    foo.persist();
+    foo2.persist();
+    return foo;
+  }
+
   public static List<SimpleFoo> findAll() {
     return new ArrayList<SimpleFoo>(get().values());
   }
@@ -86,7 +97,7 @@
       Map<Long, SimpleFoo> value = (Map<Long, SimpleFoo>) req.getSession().getAttribute(
           SimpleFoo.class.getCanonicalName());
       if (value == null) {
-        value = reset();
+        value = resetImpl();
       }
       return value;
     }
@@ -108,6 +119,36 @@
     return list;
   }
 
+  public static SimpleFoo getSimpleFooWithSubPropertyCollection() {
+    SimpleFoo foo = new SimpleFoo();
+    SimpleFoo subFoo = new SimpleFoo();
+    SimpleFoo subSubFoo = new SimpleFoo();
+    subFoo.setFooField(subSubFoo);
+    subSubFoo.setUserName("I'm here");
+    subSubFoo.persist();
+    subFoo.persist();
+    foo.persist();
+    foo.setSelfOneToManyField(Arrays.asList(subFoo));
+    return foo;
+  }
+
+  public static SimpleFoo getTripletReference() {
+    SimpleFoo foo1 = new SimpleFoo();
+    SimpleFoo foo2 = new SimpleFoo();
+    SimpleFoo foo3 = new SimpleFoo();
+    ArrayList<SimpleFoo> foos = new ArrayList<SimpleFoo>();
+    foos.add(foo2);
+    ArrayList<SimpleFoo> subFoos = new ArrayList<SimpleFoo>();
+    subFoos.add(foo3);
+    foo1.setSelfOneToManyField(foos);
+    foo2.setSelfOneToManyField(subFoos);
+    foo3.setFooField(foo2);
+    foo1.persist();
+    foo2.persist();
+    foo3.persist();
+    return foo1;
+  }
+
   public static Boolean processBooleanList(List<Boolean> values) {
     return values.get(0);
   }
@@ -191,7 +232,11 @@
     }
   }
 
-  public static synchronized Map<Long, SimpleFoo> reset() {
+  public static void reset() {
+    resetImpl();
+  }
+
+  public static synchronized Map<Long, SimpleFoo> resetImpl() {
     Map<Long, SimpleFoo> instance = new HashMap<Long, SimpleFoo>();
     // fixtures
     SimpleFoo s1 = new SimpleFoo();
@@ -275,6 +320,13 @@
 
   private List<Integer> numberListField;
 
+  /*
+   * isChanged is just a quick-and-dirty way to get version-ing for now.
+   * Currently, only set by setUserName and setIntId. TODO for later: Use a
+   * cleaner solution to figure out when to increment version numbers.
+   */
+  boolean isChanged;
+
   public SimpleFoo() {
     intId = 42;
     version = 1;
@@ -297,10 +349,12 @@
     nullField = null;
     barNullField = null;
     pleaseCrash = 0;
+    isChanged = false;
   }
 
   public Long countSimpleFooWithUserNameSideEffect() {
     findSimpleFoo(1L).setUserName(userName);
+    version++;
     return countSimpleFoo();
   }
 
@@ -449,6 +503,10 @@
       isNew = false;
       get().put(getId(), this);
     }
+    if (isChanged) {
+      version++;
+      isChanged = false;
+    }
   }
 
   public SimpleFoo persistAndReturnSelf() {
@@ -547,7 +605,10 @@
   }
 
   public void setIntId(Integer id) {
-    this.intId = id;
+    if (!this.intId.equals(id)) {
+      this.intId = id;
+      isChanged = true;
+    }
   }
 
   public void setLongField(Long longField) {
@@ -604,7 +665,10 @@
   }
 
   public void setUserName(String userName) {
-    this.userName = userName;
+    if (!this.userName.equals(userName)) {
+      this.userName = userName;
+      isChanged = true;
+    }
   }
 
   public void setVersion(Integer version) {
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFooString.java b/user/test/com/google/gwt/requestfactory/server/SimpleFooString.java
index 354b2b9..d4d3eb6 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFooString.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFooString.java
@@ -73,7 +73,7 @@
       SimpleFooString value = (SimpleFooString) req.getSession().getAttribute(
           SimpleFooString.class.getCanonicalName());
       if (value == null) {
-        value = reset();
+        value = resetImpl();
       }
       return value;
     }
@@ -99,7 +99,11 @@
     return get();
   }
 
-  public static synchronized SimpleFooString reset() {
+  public static void reset() {
+    resetImpl();
+  }
+
+  public static synchronized SimpleFooString resetImpl() {
     SimpleFooString instance = new SimpleFooString();
     HttpServletRequest req = RequestFactoryServlet.getThreadLocalRequest();
     if (req == null) {
@@ -185,6 +189,7 @@
 
   public Long countSimpleFooWithUserNameSideEffect() {
     get().setUserName(userName);
+    version++;
     return 1L;
   }
 
@@ -322,6 +327,7 @@
 
   public void persist() {
     setId(nextId++ + "x");
+    version++;
   }
 
   public SimpleFooString persistAndReturnSelf() {
diff --git a/user/test/com/google/gwt/requestfactory/server/TestContextImpl.java b/user/test/com/google/gwt/requestfactory/server/TestContextImpl.java
new file mode 100644
index 0000000..f64dcee
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/TestContextImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.requestfactory.server;
+
+/**
+ * Bad service method declarations.
+ */
+public class TestContextImpl {
+
+  public static Class badReturnType() {
+    return null;
+  }
+
+  public static String mismatchedArityStatic(int x, int y, int z) {
+    return null;
+  }
+
+  public static String mismatchedParamType(String param) {
+    return null;
+  }
+
+  public static Integer mismatchedReturnType() {
+    return null;
+  }
+
+  public static String overloadedMethod() {
+    return null;
+  }
+
+  public static String overloadedMethod(String foo) {
+    return null;
+  }
+  public String getId() {
+    return null;
+  }
+
+  public String getVersion() {
+    return null;
+  }
+
+  public String mismatchedArityInstance(int x, int y) {
+    return null;
+  }
+
+  public String mismatchedStatic(String param) {
+    return null;
+  }
+
+  public static String okMethod() {
+    return null;
+  }
+
+  public static TestContextImpl okMethodProxy() {
+    return null;
+  }
+
+  public static String mismatchedNonStatic(String param) {
+    return null;
+  }
+}
+
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place3.java b/user/test/com/google/gwt/requestfactory/server/TestContextNoIdImpl.java
similarity index 72%
copy from user/test/com/google/gwt/app/place/testplaces/Place3.java
copy to user/test/com/google/gwt/requestfactory/server/TestContextNoIdImpl.java
index 2ec0c64..8e64d37 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place3.java
+++ b/user/test/com/google/gwt/requestfactory/server/TestContextNoIdImpl.java
@@ -13,14 +13,19 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.requestfactory.server;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Bad proxy, no id.
  */
-public class Place3 extends Place1 {
+public class TestContextNoIdImpl {
 
-  public Place3(String token) {
-    super(token);
+  public static TestContextNoIdImpl okMethodProxy() {
+    return null;
   }
-}
\ No newline at end of file
+
+  public String getVersion() {
+    return null;
+  }
+}
+
diff --git a/user/test/com/google/gwt/app/place/testplaces/Place3.java b/user/test/com/google/gwt/requestfactory/server/TestContextNoVersionImpl.java
similarity index 71%
copy from user/test/com/google/gwt/app/place/testplaces/Place3.java
copy to user/test/com/google/gwt/requestfactory/server/TestContextNoVersionImpl.java
index 2ec0c64..0bccfa6 100644
--- a/user/test/com/google/gwt/app/place/testplaces/Place3.java
+++ b/user/test/com/google/gwt/requestfactory/server/TestContextNoVersionImpl.java
@@ -13,14 +13,19 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.app.place.testplaces;
+package com.google.gwt.requestfactory.server;
 
 /**
- * Used by tests of {@link com.google.gwt.app.rebind.PlaceHistoryMapperGenerator}.
+ * Bad proxy, no version.
  */
-public class Place3 extends Place1 {
+public class TestContextNoVersionImpl {
 
-  public Place3(String token) {
-    super(token);
+  public static TestContextNoVersionImpl okMethodProxy() {
+    return null;
   }
-}
\ No newline at end of file
+
+  public String getId() {
+    return null;
+  }
+}
+
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index 8549959..9ae1831 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -37,6 +37,8 @@
   Request<SimpleFooProxy> echoComplex(SimpleFooProxy fooProxy,
       SimpleBarProxy barProxy);
 
+  Request<SimpleFooProxy> fetchDoubleReference();
+
   Request<List<SimpleFooProxy>> findAll();
 
   Request<SimpleFooProxy> findSimpleFooById(Long id);
@@ -45,6 +47,10 @@
 
   Request<Set<Integer>> getNumberSet();
 
+  Request<SimpleFooProxy> getSimpleFooWithSubPropertyCollection();
+
+  Request<SimpleFooProxy> getTripletReference();
+
   InstanceRequest<SimpleFooProxy, String> hello(SimpleBarProxy proxy);
 
   InstanceRequest<SimpleFooProxy, Void> persist();
@@ -59,11 +65,11 @@
 
   Request<SimpleEnum> processEnumList(List<SimpleEnum> values);
 
-  Request<String> processString(String value);
-
   InstanceRequest<SimpleFooProxy, String> processList(
       List<SimpleFooProxy> values);
 
+  Request<String> processString(String value);
+
   InstanceRequest<SimpleFooProxy, Void> receiveNull(String value);
 
   Request<Void> receiveNullList(List<SimpleFooProxy> value);
diff --git a/user/test/com/google/gwt/text/TextSuite.gwt.xml b/user/test/com/google/gwt/text/TextSuite.gwt.xml
new file mode 100644
index 0000000..de4eae9
--- /dev/null
+++ b/user/test/com/google/gwt/text/TextSuite.gwt.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
+<module>
+	<inherits name="com.google.gwt.text.Text" />
+	<source path="client"/>
+</module>
\ No newline at end of file
diff --git a/user/test/com/google/gwt/text/TextSuite.java b/user/test/com/google/gwt/text/TextSuite.java
new file mode 100644
index 0000000..cfe30d3
--- /dev/null
+++ b/user/test/com/google/gwt/text/TextSuite.java
@@ -0,0 +1,39 @@
+/*
+ * 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.text;
+
+import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.text.client.DateTimeFormatRendererTest;
+import com.google.gwt.text.client.DoubleParserTest;
+import com.google.gwt.text.client.IntegerParserTest;
+import com.google.gwt.text.client.LongParserTest;
+
+import junit.framework.Test;
+
+/**
+ * Tests of com.google.gwt.text.
+ */
+public class TextSuite {
+  public static Test suite() {
+    GWTTestSuite suite = new GWTTestSuite(
+        "Tests of com.google.gwt.text");
+    suite.addTestSuite(DateTimeFormatRendererTest.class);
+    suite.addTestSuite(DoubleParserTest.class);
+    suite.addTestSuite(IntegerParserTest.class);
+    suite.addTestSuite(LongParserTest.class);
+    return suite;
+  }
+}
diff --git a/user/test/com/google/gwt/text/client/DateTimeFormatRendererTest.java b/user/test/com/google/gwt/text/client/DateTimeFormatRendererTest.java
new file mode 100644
index 0000000..d9844fe
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/DateTimeFormatRendererTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.text.client;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.Date;
+
+/**
+ * Eponymous unit test.
+ */
+public class DateTimeFormatRendererTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.text.TextSuite";
+  }
+
+  public void testDefault() {
+    Date d = new Date(39874748234L);
+
+    assertEquals(
+        DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT).format(d),
+        new DateTimeFormatRenderer().render(d));
+  }
+
+  public void testFull() {
+    Date d = new Date(3983374748234L);
+    DateTimeFormat f = DateTimeFormat.getFormat(PredefinedFormat.DATE_FULL);
+    TimeZone t = TimeZone.createTimeZone(180);
+
+    assertEquals(f.format(d, t), new DateTimeFormatRenderer(f, t).render(d));
+  }
+
+  public void testNoTz() {
+    Date d = new Date(3983374748234L);
+    DateTimeFormat f = DateTimeFormat.getFormat(PredefinedFormat.DATE_FULL);
+
+    assertEquals(f.format(d), new DateTimeFormatRenderer(f).render(d));
+  }
+
+  public void testNull() {
+    assertEquals("", new DateTimeFormatRenderer().render(null));
+  }
+}
diff --git a/user/test/com/google/gwt/text/client/DoubleParserTest.java b/user/test/com/google/gwt/text/client/DoubleParserTest.java
new file mode 100644
index 0000000..d14414d
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/DoubleParserTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.text.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.text.ParseException;
+
+/**
+ * Eponymous unit test.
+ */
+public class DoubleParserTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.text.TextSuite";
+  }
+  
+  public void testOuroborus() throws ParseException {
+    assertEquals("123", DoubleRenderer.instance().render(DoubleParser.instance().parse("123")));
+  }
+  
+  public void testNull() throws ParseException {
+    assertEquals("", DoubleRenderer.instance().render(DoubleParser.instance().parse("")));
+  }
+}
diff --git a/user/test/com/google/gwt/text/client/IntegerParserTest.java b/user/test/com/google/gwt/text/client/IntegerParserTest.java
new file mode 100644
index 0000000..85f922d
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/IntegerParserTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.text.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.text.ParseException;
+
+/**
+ * Eponymous unit test.
+ */
+public class IntegerParserTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.text.TextSuite";
+  }
+  
+  public void testOuroborus() throws ParseException {
+    assertEquals("123", IntegerRenderer.instance().render(IntegerParser.instance().parse("123")));
+  }
+  
+  public void testNull() throws ParseException {
+    assertEquals("", IntegerRenderer.instance().render(IntegerParser.instance().parse("")));
+  }
+}
diff --git a/user/test/com/google/gwt/text/client/LongParserTest.java b/user/test/com/google/gwt/text/client/LongParserTest.java
new file mode 100644
index 0000000..25e72c0
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/LongParserTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.text.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.text.ParseException;
+
+/**
+ * Eponymous unit test.
+ */
+public class LongParserTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.text.TextSuite";
+  }
+  
+  public void testOuroborus() throws ParseException {
+    assertEquals("123", LongRenderer.instance().render(LongParser.instance().parse("123")));
+  }
+  
+  public void testNull() throws ParseException {
+    assertEquals("", LongRenderer.instance().render(LongParser.instance().parse("")));
+  }
+}
diff --git a/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java b/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java
index 5a1c40f..2b825f1 100644
--- a/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java
@@ -351,6 +351,18 @@
     view.assertSelectedRows();
   }
 
+  public void testDefaults() {
+    HasData<String> listView = new MockHasData<String>();
+    MockView<String> view = new MockView<String>();
+    HasDataPresenter<String> presenter = new HasDataPresenter<String>(listView,
+        view, 10, null);
+
+    assertEquals(0, presenter.getRowCount());
+    assertFalse(presenter.isRowCountExact());
+    assertEquals(0, presenter.getCurrentPageSize());
+    assertEquals(new Range(0, 10), presenter.getVisibleRange());
+  }
+
   public void testGetCurrentPageSize() {
     HasData<String> listView = new MockHasData<String>();
     MockView<String> view = new MockView<String>();
@@ -884,10 +896,17 @@
     assertTrue(presenter.isRowCountExact());
     view.assertLoadingState(LoadingState.LOADING);
 
-    // Set size to 0.
+    // Set size to 0, but not exact. The state is loading until we know there is
+    // no data.
     presenter.setRowCount(0, false);
     assertEquals(0, presenter.getRowCount());
     assertFalse(presenter.isRowCountExact());
+    view.assertLoadingState(LoadingState.LOADING);
+
+    // Set size to 0 and exact. Now we know the list is empty.
+    presenter.setRowCount(0, true);
+    assertEquals(0, presenter.getRowCount());
+    assertTrue(presenter.isRowCountExact());
     view.assertLoadingState(LoadingState.EMPTY);
   }
 
diff --git a/user/test/com/google/gwt/user/client/ui/ValueBoxBaseTest.java b/user/test/com/google/gwt/user/client/ui/ValueBoxBaseTest.java
index da8d0ff..65a2ae1 100644
--- a/user/test/com/google/gwt/user/client/ui/ValueBoxBaseTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ValueBoxBaseTest.java
@@ -18,8 +18,8 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.text.shared.PassthroughRenderer;
 import com.google.gwt.text.shared.Renderer;
+import com.google.gwt.text.shared.testing.PassthroughRenderer;
 
 import java.text.ParseException;
 
@@ -35,7 +35,8 @@
     MockParser parser = new MockParser();
     
     ValueBoxBase<String> valueBoxBase = 
-      new ValueBoxBase<String>(elm, renderer, parser);
+      new ValueBoxBase<String>(elm, renderer, parser) {
+    };
     
     parser.throwException = true;
     valueBoxBase.setText("");
@@ -57,7 +58,8 @@
     MockParser parser = new MockParser();
     
     ValueBoxBase<String> valueBoxBase = 
-      new ValueBoxBase<String>(elm, renderer, parser);
+      new ValueBoxBase<String>(elm, renderer, parser) {
+    };
     
     parser.throwException = true;
     valueBoxBase.setText("simple string");
@@ -79,7 +81,8 @@
     MockParser parser = new MockParser();
     
     ValueBoxBase<String> valueBoxBase = 
-      new ValueBoxBase<String>(elm, renderer, parser);
+      new ValueBoxBase<String>(elm, renderer, parser) {
+    };
     
     String text = "  two space padding test  ";
     valueBoxBase.setText(text);