Resolve ROO-1452.
Allows RequestFactory service methods to return null values.
Patch by: bobv
Review by: rjrjr


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8867 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
index 0cf012c..290f801 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
@@ -59,8 +59,8 @@
       final DynaTableRequestFactory requestFactory,
       final FavoritesManager manager) {
     eventBus.addHandler(EditPersonEvent.TYPE, new EditPersonEvent.Handler() {
-      public void startEdit(PersonProxy person) {
-        new PersonEditorWorkflow(requestFactory, manager, person).edit();
+      public void startEdit(PersonProxy person, Request<?> request) {
+        new PersonEditorWorkflow(requestFactory, manager, person).edit(request);
       }
     });
   }
@@ -79,7 +79,7 @@
 
   private Driver editorDriver;
   private final FavoritesManager manager;
-  private final PersonProxy person;
+  private PersonProxy person;
   private final DynaTableRequestFactory requestFactory;
 
   private PersonEditorWorkflow(DynaTableRequestFactory requestFactory,
@@ -98,12 +98,12 @@
   }
 
   @UiHandler("cancel")
-  void onCancel(@SuppressWarnings("unused") ClickEvent e) {
+  void onCancel(ClickEvent e) {
     dialog.hide();
   }
 
   @UiHandler("save")
-  void onSave(@SuppressWarnings("unused") ClickEvent e) {
+  void onSave(ClickEvent e) {
     // MOVE TO ACTIVITY END
     final Request<Void> request = editorDriver.<Void> flush();
     if (editorDriver.hasErrors()) {
@@ -125,18 +125,28 @@
   }
 
   @UiHandler("favorite")
-  void onValueChanged(@SuppressWarnings("unused") ValueChangeEvent<Boolean> event) {
+  void onValueChanged(ValueChangeEvent<Boolean> event) {
     manager.setFavorite(person, favorite.getValue());
   }
 
-  private void edit() {
-    // The request is configured arbitrarily
-    ProxyRequest<PersonProxy> fetchRequest = requestFactory.personRequest().findPerson(
-        person.getId());
-
+  private void edit(Request<?> request) {
     editorDriver = GWT.create(Driver.class);
-    editorDriver.initialize(null, requestFactory, personEditor);
+    editorDriver.initialize(requestFactory, personEditor);
 
+    if (request == null) {
+      fetchAndEdit();
+      return;
+    }
+
+    editorDriver.edit(person, request);
+    personEditor.focus();
+    favorite.setValue(manager.isFavorite(person), false);
+    dialog.center();
+  }
+
+  private void fetchAndEdit() {
+    // The request is configured arbitrarily
+    ProxyRequest<PersonProxy> fetchRequest = requestFactory.find(person.stableId());
     // Add the paths that the EditorDelegate computes are necessary
     fetchRequest.with(editorDriver.getPaths());
 
@@ -144,15 +154,11 @@
     fetchRequest.fire(new Receiver<PersonProxy>() {
       @Override
       public void onSuccess(PersonProxy person) {
+        PersonEditorWorkflow.this.person = person;
         // Start the edit process
-        editorDriver.edit(person,
-            requestFactory.personRequest().persist(person));
-        personEditor.focus();
+        Request<Void> request = requestFactory.personRequest().persist(person);
+        edit(request);
       }
     });
-
-    // Set up UI while waiting for data
-    favorite.setValue(manager.isFavorite(person), false);
-    dialog.center();
   }
 }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/EditPersonEvent.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/EditPersonEvent.java
index 744cddd..737ff85 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/EditPersonEvent.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/EditPersonEvent.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.requestfactory.shared.Request;
 import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
 
 /**
@@ -31,18 +32,24 @@
    * Handles {@link EditPersonEvent}.
    */
   public interface Handler extends EventHandler {
-    void startEdit(PersonProxy person);
+    void startEdit(PersonProxy person, Request<?> request);
   }
 
   private final PersonProxy person;
+  private final Request<?> request;
 
   public EditPersonEvent(PersonProxy person) {
+    this(person, null);
+  }
+
+  public EditPersonEvent(PersonProxy person, Request<?> request) {
     this.person = person;
+    this.request = request;
   }
 
   @Override
   protected void dispatch(Handler handler) {
-    handler.startEdit(person);
+    handler.startEdit(person, request);
   }
 
   @Override
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/FilterChangeEvent.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/FilterChangeEvent.java
index b9bcf98..5cb4864 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/FilterChangeEvent.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/events/FilterChangeEvent.java
@@ -15,8 +15,10 @@
  */
 package com.google.gwt.sample.dynatablerf.client.events;
 
+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.HandlerRegistration;
 
 /**
  * An event to indicate a change in the filter options.
@@ -30,6 +32,11 @@
   }
 
   public static final Type<Handler> TYPE = new Type<Handler>();
+
+  public static HandlerRegistration register(EventBus eventBus, Handler handler) {
+    return eventBus.addHandler(TYPE, handler);
+  }
+
   private final int day;
   private final boolean selected;
 
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/DayCheckBox.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/DayCheckBox.java
index 128b82c..79a1fc4 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/DayCheckBox.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/DayCheckBox.java
@@ -35,7 +35,7 @@
   public DayCheckBox(EventBus eventBus) {
     this.eventBus = eventBus;
     initWidget(cb);
-    cb.setEnabled(false);
+    cb.setValue(true);
     cb.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
       public void onValueChange(ValueChangeEvent<Boolean> event) {
         DayCheckBox.this.eventBus.fireEvent(new FilterChangeEvent(getDay(),
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java
index 580d410..62e87d6 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java
@@ -86,7 +86,7 @@
   @UiField
   Style style;
 
-  private final List<PersonProxy> displayed;
+  private final List<PersonProxy> displayedList;
   private final EventBus eventBus;
   private final RequestFactory factory;
   private FavoritesManager manager;
@@ -117,7 +117,7 @@
     driver.display(new ArrayList<PersonProxy>());
 
     // Modifying this list triggers widget creation and destruction
-    displayed = listEditor.getList();
+    displayedList = listEditor.getList();
   }
 
   @Override
@@ -149,16 +149,32 @@
       return;
     }
 
-    if (event.isFavorite()) {
-      displayed.add(person);
+    // EntityProxies should be compared by stable id
+    EntityProxyId<PersonProxy> lookFor = person.stableId();
+    PersonProxy found = null;
+    for (PersonProxy displayed : displayedList) {
+      if (displayed.stableId().equals(lookFor)) {
+        found = displayed;
+        break;
+      }
+    }
+
+    if (event.isFavorite() && found == null) {
+      displayedList.add(person);
+    } else if (!event.isFavorite() && found != null) {
+      displayedList.remove(person);
     } else {
-      displayed.remove(person);
+      // No change
+      return;
     }
 
     // Sorting the list of PersonProxies will also change the UI display
-    Collections.sort(displayed, new Comparator<PersonProxy>() {
+    Collections.sort(displayedList, new Comparator<PersonProxy>() {
       public int compare(PersonProxy o1, PersonProxy o2) {
-        return o1.getName().compareTo(o2.getName());
+        // Newly-created records may have null names
+        String name1 = o1.getName() == null ? "" : o1.getName();
+        String name2 = o2.getName() == null ? "" : o2.getName();
+        return name1.compareToIgnoreCase(name2);
       }
     });
   }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
index f7a8c31..4e2dbcf 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
@@ -17,13 +17,17 @@
 
 import com.google.gwt.cell.client.TextCell;
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.shared.EventBus;
 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.resources.client.CssResource;
 import com.google.gwt.sample.dynatablerf.client.events.EditPersonEvent;
+import com.google.gwt.sample.dynatablerf.client.events.FilterChangeEvent;
+import com.google.gwt.sample.dynatablerf.shared.AddressProxy;
 import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
 import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
 import com.google.gwt.uibinder.client.UiBinder;
@@ -111,6 +115,9 @@
   private final DynaTableRequestFactory requestFactory;
   private final SingleSelectionModel<PersonProxy> selectionModel = new SingleSelectionModel<PersonProxy>();
 
+  private boolean[] filter = new boolean[] {
+      true, true, true, true, true, true, true};
+
   public SummaryWidget(EventBus eventBus,
       DynaTableRequestFactory requestFactory, int numRows) {
     this.eventBus = eventBus;
@@ -139,6 +146,13 @@
           }
         });
 
+    FilterChangeEvent.register(eventBus, new FilterChangeEvent.Handler() {
+      public void onFilterChanged(FilterChangeEvent e) {
+        filter[e.getDay()] = e.isSelected();
+        fetch(0);
+      }
+    });
+
     selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
       public void onSelectionChange(SelectionChangeEvent event) {
         SummaryWidget.this.refreshSelection();
@@ -148,6 +162,16 @@
     fetch(0);
   }
 
+  @UiHandler("create")
+  void onCreate(ClickEvent event) {
+    AddressProxy address = requestFactory.create(AddressProxy.class);
+    PersonProxy person = requestFactory.create(PersonProxy.class);
+    Request<Void> request = requestFactory.personRequest().persist(person);
+    person = request.edit(person);
+    person.setAddress(address);
+    eventBus.fireEvent(new EditPersonEvent(person, request));
+  }
+
   void onPersonChanged(EntityProxyChange<PersonProxy> event) {
     if (WriteOperation.UPDATE.equals(event.getWriteOperation())) {
       EntityProxyId<PersonProxy> personId = event.getProxyId();
@@ -156,18 +180,17 @@
       int displayOffset = offsetOf(personId);
       if (displayOffset != -1) {
         // Record is onscreen and may differ from our data
-        requestFactory.find(personId).fire(
-            new Receiver<PersonProxy>() {
-              @Override
-              public void onSuccess(PersonProxy person) {
-                // Re-check offset in case of changes while waiting for data
-                int offset = offsetOf(person.stableId());
-                if (offset != -1) {
-                  table.setRowData(table.getPageStart() + offset,
-                      Collections.singletonList(person));
-                }
-              }
-            });
+        requestFactory.find(personId).fire(new Receiver<PersonProxy>() {
+          public void onSuccess(PersonProxy response) {
+            PersonProxy person = (PersonProxy) response;
+            // Re-check offset in case of changes while waiting for data
+            int offset = offsetOf(person.stableId());
+            if (offset != -1) {
+              table.setRowData(table.getPageStart() + offset,
+                  Collections.singletonList(person));
+            }
+          }
+        });
       }
     }
   }
@@ -185,11 +208,12 @@
     if (person == null) {
       return;
     }
-    SummaryWidget.this.eventBus.fireEvent(new EditPersonEvent(person));
+    eventBus.fireEvent(new EditPersonEvent(person));
     selectionModel.setSelected(person, false);
   }
 
   private void fetch(final int start) {
+    // XXX add back filter
     requestFactory.schoolCalendarRequest().getPeople(start, numRows).fire(
         new Receiver<List<PersonProxy>>() {
           @Override
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.ui.xml
index 411a374..f7e7269 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.ui.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.ui.xml
@@ -3,21 +3,30 @@
   <ui:style src="../common.css"
     type="com.google.gwt.sample.dynatablerf.client.widgets.SummaryWidget.Style">
       .displayInline {
-        display: inline;
+      	display: inline;
       }
       
       .thirty {
-        width: 30%
+      	width: 30%
       }
     </ui:style>
   <g:DockLayoutPanel ui:field="dock" unit="EX">
     <g:north size="6">
-      <g:HTMLPanel>
-        <div class="{style.rightAlign}">
-          <cv:SimplePager ui:field="pager" stylePrimaryName="{style.displayInline}"
-            display="{table}" />
-        </div>
-      </g:HTMLPanel>
+      <g:DockLayoutPanel unit="PCT">
+        <g:east size="45">
+          <g:SimplePanel stylePrimaryName="{style.rightAlign}">
+            <cv:SimplePager ui:field="pager" stylePrimaryName="{style.displayInline}"
+              display="{table}" />
+          </g:SimplePanel>
+        </g:east>
+        <g:west size="45">
+          <g:SimplePanel>
+            <g:Button stylePrimaryName="{style.displayInline}"
+              ui:field="create">New
+              Person</g:Button>
+          </g:SimplePanel>
+        </g:west>
+      </g:DockLayoutPanel>
     </g:north>
     <g:center>
       <cv:CellTable ui:field="table" />
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Address.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Address.java
index bed0090..b87ee48 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Address.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Address.java
@@ -37,7 +37,7 @@
   @Size(min = 1)
   private String city;
 
-  @NotNull
+  // May be null if Address is newly-created
   private String id;
 
   @NotNull
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
index b7b2dda..7e5caca 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
@@ -24,7 +24,15 @@
 /**
  * Hold relevant data for Person.
  */
-public abstract class Person {
+public class Person {
+  /**
+   * New instances could be created on the client, but it's a better demo to
+   * send back a Person with a bunch of dummy data.
+   */
+  public static Person createPerson() {
+    return SchoolCalendarService.createPerson();
+  }
+
   /**
    * The RequestFactory requires a static finder method for each proxied type.
    * Soon it should allow you to customize how instances are found.
@@ -41,13 +49,16 @@
   private final Address address = new Address();
 
   @NotNull
+  private Schedule classSchedule = new Schedule();
+
+  @NotNull
   private String description = "DESC";
 
   @NotNull
   @Size(min = 2, message = "Persons aren't just characters")
   private String name;
 
-  @NotNull
+  // May be null if the person is newly-created
   private String id;
 
   @NotNull
@@ -56,6 +67,9 @@
 
   private String note;
 
+  private final boolean[] daysFilters = new boolean[] {
+      true, true, true, true, true, true, true};
+
   public Person() {
   }
 
@@ -65,6 +79,7 @@
 
   public void copyFrom(Person copyFrom) {
     address.copyFrom(copyFrom.address);
+    classSchedule = copyFrom.classSchedule;
     description = copyFrom.description;
     name = copyFrom.name;
     id = copyFrom.id;
@@ -76,6 +91,10 @@
     return address;
   }
 
+  public Schedule getClassSchedule() {
+    return classSchedule;
+  }
+
   public String getDescription() {
     return description;
   }
@@ -100,10 +119,12 @@
   }
 
   public String getSchedule() {
-    return getSchedule(new boolean[] {true, true, true, true, true, true, true});
+    return getSchedule(daysFilters);
   }
 
-  public abstract String getSchedule(boolean[] daysFilter);
+  public String getSchedule(boolean[] daysFilter) {
+    return classSchedule.getDescription(daysFilter);
+  }
 
   /**
    * The RequestFactory requires an Integer version property for each proxied
@@ -113,7 +134,9 @@
     return version;
   }
 
-  public abstract Person makeCopy();
+  public Person makeCopy() {
+    return new Person(this);
+  }
 
   /**
    * When this was written the RequestFactory required a persist method per
@@ -124,6 +147,16 @@
     SchoolCalendarService.persist(this);
   }
 
+  public void setAddress(Address address) {
+    this.address.copyFrom(address);
+  }
+
+  public void setDaysFilter(boolean[] daysFilter) {
+    assert daysFilter.length == this.daysFilters.length;
+    System.arraycopy(daysFilter, 0, this.daysFilters, 0,
+        this.daysFilters.length);
+  }
+
   public void setDescription(String description) {
     this.description = description;
   }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Professor.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Professor.java
deleted file mode 100644
index 3e3a296..0000000
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Professor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.dynatablerf.domain;
-
-/**
- * Holds relevant data for a Professor type Person.
- */
-public class Professor extends Person {
-
-  private Schedule teachingSchedule = new Schedule();
-
-  public Professor() {
-  }
-
-  private Professor(Professor copyFrom) {
-    super(copyFrom);
-    teachingSchedule = copyFrom.teachingSchedule;
-  }
-
-  @Override
-  public String getSchedule(boolean[] daysFilter) {
-    return teachingSchedule.getDescription(daysFilter);
-  }
-
-  public Schedule getTeachingSchedule() {
-    return teachingSchedule;
-  }
-
-  @Override
-  public Professor makeCopy() {
-    return new Professor(this);
-  }
-}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Student.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Student.java
deleted file mode 100644
index c7be880..0000000
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Student.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.dynatablerf.domain;
-
-/**
- * Holds relevant data for a Student type Person.
- */
-public class Student extends Person {
-
-  private Schedule classSchedule = new Schedule();
-
-  public Student() {
-  }
-
-  private Student(Student copyFrom) {
-    super(copyFrom);
-    classSchedule = copyFrom.classSchedule;
-  }
-
-  public Schedule getClassSchedule() {
-    return classSchedule;
-  }
-
-  @Override
-  public String getSchedule(boolean[] daysFilter) {
-    return classSchedule.getDescription(daysFilter);
-  }
-
-  @Override
-  public Student makeCopy() {
-    return new Student(this);
-  }
-}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
index 9bbfaba..3a0c79b 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
@@ -16,9 +16,7 @@
 package com.google.gwt.sample.dynatablerf.server;
 
 import com.google.gwt.sample.dynatablerf.domain.Person;
-import com.google.gwt.sample.dynatablerf.domain.Professor;
 import com.google.gwt.sample.dynatablerf.domain.Schedule;
-import com.google.gwt.sample.dynatablerf.domain.Student;
 import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
 
 import java.util.ArrayList;
@@ -54,6 +52,13 @@
 
   private static final int STUDENTS_PER_PROF = 5;
 
+  public static Person generatePerson() {
+    Random rnd = new Random();
+    Person toReturn = generateRandomPerson(rnd);
+    AddressFuzzer.fuzz(rnd, toReturn.getAddress());
+    return toReturn;
+  }
+
   public static List<Person> generateRandomPeople() {
     List<Person> toReturn = new ArrayList<Person>(MAX_PEOPLE);
     Random rnd = new Random(3);
@@ -76,7 +81,7 @@
   }
 
   private static Person generateRandomProfessor(Random rnd) {
-    Professor prof = new Professor();
+    Person prof = new Person();
 
     String firstName = pickRandomString(rnd, FIRST_NAMES);
     String lastName = pickRandomString(rnd, LAST_NAMES);
@@ -85,7 +90,7 @@
     String subject = pickRandomString(rnd, SUBJECTS);
     prof.setDescription("Professor of " + subject);
 
-    generateRandomSchedule(rnd, prof.getTeachingSchedule());
+    generateRandomSchedule(rnd, prof.getClassSchedule());
 
     return prof;
   }
@@ -115,7 +120,7 @@
   }
 
   private static Person generateRandomStudent(Random rnd) {
-    Student student = new Student();
+    Person student = new Person();
 
     String firstName = pickRandomString(rnd, FIRST_NAMES);
     String lastName = pickRandomString(rnd, LAST_NAMES);
@@ -133,5 +138,4 @@
     int i = rnd.nextInt(a.length);
     return a[i];
   }
-
 }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
index 5db0d1c..08ec81c 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
@@ -42,7 +42,8 @@
     }
 
     @Override
-    public List<Person> getPeople(int startIndex, int maxCount) {
+    public List<Person> getPeople(int startIndex, int maxCount,
+        boolean[] daysFilter) {
       int peopleCount = countPeople();
 
       int start = startIndex;
@@ -54,6 +55,7 @@
       if (start == end) {
         return Collections.emptyList();
       }
+      // This is ugly, but a real backend would have a skip mechanism
       return new ArrayList<Person>(people.values()).subList(start, end);
     }
 
@@ -104,10 +106,14 @@
     }
 
     @Override
-    public List<Person> getPeople(int startIndex, int maxCount) {
+    public List<Person> getPeople(int startIndex, int maxCount,
+        boolean[] daysFilter) {
       List<Person> toReturn = new ArrayList<Person>(maxCount);
-      for (Person person : backingStore.getPeople(startIndex, maxCount)) {
-        toReturn.add(findPerson(person.getId()));
+      for (Person person : backingStore.getPeople(startIndex, maxCount,
+          daysFilter)) {
+        Person copy = findPerson(person.getId());
+        toReturn.add(copy);
+        copy.setDaysFilter(daysFilter);
       }
       return toReturn;
     }
@@ -148,7 +154,8 @@
 
   public abstract Person findPerson(String id);
 
-  public abstract List<Person> getPeople(int startIndex, int maxCount);
+  public abstract List<Person> getPeople(int startIndex, int maxCount,
+      boolean[] daysFilter);
 
   public abstract void persist(Address address);
 
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
index 61170f2..3cdc9a8 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
@@ -34,14 +34,24 @@
 public class SchoolCalendarService implements Filter {
   private static final ThreadLocal<PersonSource> PERSON_SOURCE = new ThreadLocal<PersonSource>();
 
+  public static Person createPerson() {
+    checkPersonSource();
+    Person person = PersonFuzzer.generatePerson();
+    PERSON_SOURCE.get().persist(person);
+    return person;
+  }
+
   public static Person findPerson(String id) {
     checkPersonSource();
     return PERSON_SOURCE.get().findPerson(id);
   }
 
+  /**
+   * XXX Remove this once primitive lists work.
+   */
   public static List<Person> getPeople(int startIndex, int maxCount) {
-    checkPersonSource();
-    return PERSON_SOURCE.get().getPeople(startIndex, maxCount);
+    return getPeople(startIndex, maxCount, new boolean[] {
+        true, true, true, true, true, true, true});
   }
 
   public static void persist(Address address) {
@@ -61,6 +71,15 @@
     }
   }
 
+  /**
+   * XXX private due to inability to add method overloads.
+   */
+  private static List<Person> getPeople(int startIndex, int maxCount,
+      boolean[] filter) {
+    checkPersonSource();
+    return PERSON_SOURCE.get().getPeople(startIndex, maxCount, filter);
+  }
+
   private PersonSource backingStore;
 
   public void destroy() {
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
index c76996c..a08e09a 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
@@ -18,7 +18,6 @@
 import com.google.gwt.requestfactory.shared.Instance;
 import com.google.gwt.requestfactory.shared.LoggingRequest;
 import com.google.gwt.requestfactory.shared.ProxyListRequest;
-import com.google.gwt.requestfactory.shared.ProxyRequest;
 import com.google.gwt.requestfactory.shared.Request;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.requestfactory.shared.Service;
@@ -37,8 +36,6 @@
    */
   @Service(Address.class)
   interface AddressRequest {
-    ProxyRequest<AddressProxy> findAddress(String id);
-
     @Instance
     Request<Void> persist(AddressProxy person);
   }
@@ -48,8 +45,6 @@
    */
   @Service(Person.class)
   interface PersonRequest {
-    ProxyRequest<PersonProxy> findPerson(String id);
-
     @Instance
     Request<Void> persist(PersonProxy person);
   }
@@ -59,7 +54,6 @@
    */
   @Service(SchoolCalendarService.class)
   interface SchoolCalendarRequest {
-    // TODO(amitmanjhi, cromwellian) Request<List<PersonProxy>>
     ProxyListRequest<PersonProxy> getPeople(int startIndex, int maxCount);
   }
 
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
index 31413a5..deae1b3 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
@@ -38,6 +38,8 @@
 
   String getSchedule();
 
+  void setAddress(AddressProxy address);
+
   void setDescription(String description);
 
   void setName(String name);
diff --git a/user/src/com/google/gwt/editor/client/EditorDelegate.java b/user/src/com/google/gwt/editor/client/EditorDelegate.java
index 1e56034..d51c32b 100644
--- a/user/src/com/google/gwt/editor/client/EditorDelegate.java
+++ b/user/src/com/google/gwt/editor/client/EditorDelegate.java
@@ -33,15 +33,6 @@
  */
 public interface EditorDelegate<T> {
   /**
-   * If a {@link ValueAwareEditor} chooses to modify the object passed into
-   * {@link ValueAwareEditor#setValue} directly, as opposed to manipulating its
-   * sub-Editors, the Editor must only call setter methods on the object
-   * returned from this method. This allows the backing service to optimize the
-   * read-only use case.
-   */
-  T ensureMutable(T object);
-
-  /**
    * Returns the Editor's path, relative to the root object.
    */
   String getPath();
diff --git a/user/src/com/google/gwt/editor/client/ValueAwareEditor.java b/user/src/com/google/gwt/editor/client/ValueAwareEditor.java
index 1d846bc..84da806 100644
--- a/user/src/com/google/gwt/editor/client/ValueAwareEditor.java
+++ b/user/src/com/google/gwt/editor/client/ValueAwareEditor.java
@@ -39,11 +39,7 @@
    * Called by the EditorDriver to set the object the Editor is peered with
    * <p>
    * ValueAwareEditors should preferentially use sub-editors to alter the
-   * properties of the object being edited. If this is not feasible, the value
-   * provided to this method must not be mutated directly without calling
-   * {@link EditorDelegate#ensureMutable()} to obtain a guaranteed-mutable
-   * instance.
-   * <p>
+   * properties of the object being edited.
    */
   void setValue(T value);
 }
diff --git a/user/src/com/google/gwt/editor/client/adapters/TakesValueEditor.java b/user/src/com/google/gwt/editor/client/adapters/TakesValueEditor.java
index 1cb1b0f..2472e85 100644
--- a/user/src/com/google/gwt/editor/client/adapters/TakesValueEditor.java
+++ b/user/src/com/google/gwt/editor/client/adapters/TakesValueEditor.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.editor.client.adapters;
 
-import com.google.gwt.editor.client.EditorDelegate;
-import com.google.gwt.editor.client.HasEditorDelegate;
 import com.google.gwt.editor.client.LeafValueEditor;
 import com.google.gwt.user.client.TakesValue;
 
@@ -25,14 +23,12 @@
  * 
  * @param <T> the type of value to be edited
  */
-public class TakesValueEditor<T> implements LeafValueEditor<T>,
-    HasEditorDelegate<T> {
+public class TakesValueEditor<T> implements LeafValueEditor<T> {
 
   public static <T> TakesValueEditor<T> of(TakesValue<T> peer) {
     return new TakesValueEditor<T>(peer);
   }
 
-  private EditorDelegate<T> delegate;
   private final TakesValue<T> peer;
 
   protected TakesValueEditor(TakesValue<T> peer) {
@@ -43,19 +39,7 @@
     return peer.getValue();
   }
 
-  public void setDelegate(EditorDelegate<T> delegate) {
-    this.delegate = delegate;
-  }
-
   public void setValue(T value) {
-    peer.setValue(delegate.ensureMutable(value));
-  }
-
-  protected EditorDelegate<T> getDelegate() {
-    return delegate;
-  }
-
-  protected TakesValue<T> getPeer() {
-    return peer;
+    peer.setValue(value);
   }
 }
diff --git a/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java b/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java
index d34d270..0433197 100644
--- a/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java
+++ b/user/src/com/google/gwt/editor/client/adapters/ValueBoxEditor.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.editor.client.adapters;
 
+import com.google.gwt.editor.client.EditorDelegate;
+import com.google.gwt.editor.client.HasEditorDelegate;
 import com.google.gwt.user.client.ui.ValueBoxBase;
 
 import java.text.ParseException;
@@ -26,12 +28,14 @@
  * 
  * @param <T> the type of value to be edited
  */
-public class ValueBoxEditor<T> extends TakesValueEditor<T> {
+public class ValueBoxEditor<T> extends TakesValueEditor<T> implements
+    HasEditorDelegate<T> {
 
   public static <T> ValueBoxEditor<T> of(ValueBoxBase<T> valueBox) {
     return new ValueBoxEditor<T>(valueBox);
   }
 
+  private EditorDelegate<T> delegate;
   private final ValueBoxBase<T> peer;
   private T value;
 
@@ -40,6 +44,10 @@
     this.peer = peer;
   }
 
+  public EditorDelegate<T> getDelegate() {
+    return delegate;
+  }
+
   /**
    * Calls {@link ValueBoxBase#getValueOrThrow()}. If a {@link ParseException}
    * is thrown, it will be available through
@@ -58,6 +66,10 @@
     return value;
   }
 
+  public void setDelegate(EditorDelegate<T> delegate) {
+    this.delegate = delegate;
+  }
+
   @Override
   public void setValue(T value) {
     peer.setValue(this.value = value);
diff --git a/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java b/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java
index 5af1c44..911d743 100644
--- a/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java
+++ b/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java
@@ -123,8 +123,6 @@
     super();
   }
 
-  public abstract T ensureMutable(T object);
-
   /**
    * Flushes both data and errors.
    */
@@ -143,7 +141,6 @@
       if (getObject() == null) {
         return;
       }
-      setObject(ensureMutable(getObject()));
       flushSubEditors(errors);
 
       if (editorChain != null) {
@@ -178,7 +175,7 @@
   }
 
   public void refresh(T object) {
-    setObject(object);
+    setObject(ensureMutable(object));
     if (leafValueEditor != null) {
       leafValueEditor.setValue(object);
     } else if (valueAwareEditor != null) {
@@ -202,6 +199,10 @@
     throw new IllegalStateException();
   }
 
+  protected <Q> Q ensureMutable(Q object) {
+    return object;
+  }
+
   protected abstract void flushSubEditorErrors(
       List<EditorError> errorAccumulator);
 
@@ -217,7 +218,7 @@
       DelegateMap map) {
     this.path = pathSoFar;
     setEditor(editor);
-    setObject(object);
+    setObject(ensureMutable(object));
     errors = new ArrayList<EditorError>();
     simpleEditors = new HashMap<String, Editor<?>>();
 
diff --git a/user/src/com/google/gwt/editor/client/impl/SimpleBeanEditorDelegate.java b/user/src/com/google/gwt/editor/client/impl/SimpleBeanEditorDelegate.java
index 5638879..5fb855f 100644
--- a/user/src/com/google/gwt/editor/client/impl/SimpleBeanEditorDelegate.java
+++ b/user/src/com/google/gwt/editor/client/impl/SimpleBeanEditorDelegate.java
@@ -28,11 +28,6 @@
     AbstractEditorDelegate<T, E> {
 
   @Override
-  public T ensureMutable(T object) {
-    return object;
-  }
-
-  @Override
   public void initialize(String pathSoFar, T object, E editor, DelegateMap map) {
     super.initialize(pathSoFar, object, editor, map);
   }
diff --git a/user/src/com/google/gwt/editor/client/testing/MockEditorDelegate.java b/user/src/com/google/gwt/editor/client/testing/MockEditorDelegate.java
index 3600b79..3706468 100644
--- a/user/src/com/google/gwt/editor/client/testing/MockEditorDelegate.java
+++ b/user/src/com/google/gwt/editor/client/testing/MockEditorDelegate.java
@@ -32,13 +32,6 @@
   private String path = "";
 
   /**
-   * Returns <code>object</code>.
-   */
-  public T ensureMutable(T object) {
-    return object;
-  }
-
-  /**
    * Returns a zero-length string or the last value passed to {@link #setPath}.
    */
   public String getPath() {
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java
index 1841abf..78c8c4b 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java
@@ -67,16 +67,32 @@
   public <P extends EntityProxy> P edit(P record) {
     P returnRecordImpl = (P) ((ProxyImpl) record).schema().create(
         ((ProxyImpl) record).asJso(), ((ProxyImpl) record).unpersisted());
-    ((ProxyImpl) returnRecordImpl).putDeltaValueStore(deltaValueStore);
+    ((ProxyImpl) returnRecordImpl).putDeltaValueStore(deltaValueStore, this);
     return returnRecordImpl;
   }
 
+  /**
+   * Utility method to call {@link #edit} only on immutable proxy objects. Any
+   * other type of data will be returned as-is.
+   */
+  public <Q> Q ensureMutable(Q o) {
+    if (o instanceof ProxyImpl) {
+      ProxyImpl proxy = (ProxyImpl) o;
+      if (!proxy.mutable()) {
+        @SuppressWarnings("unchecked")
+        Q editable = (Q) edit(proxy);
+        return editable;
+      }
+    }
+    return o;
+  }
+
   public void fire(Receiver<? super T> receiver) {
     assert null != receiver : "receiver cannot be null";
     this.receiver = receiver;
     requestFactory.fire(this);
   }
-  
+
   /**
    * @deprecated use {@link #with(String...)} instead.
    * @param properties
@@ -88,7 +104,7 @@
     }
     return getThis();
   }
-  
+
   /**
    * @return the properties
    */
@@ -102,19 +118,23 @@
     JsonResults results = JsonResults.fromResults(responseText);
     JsonServerException cause = results.getException();
     if (cause != null) {
-      fail(new ServerFailure(
-          cause.getMessage(), cause.getType(), cause.getTrace()));
+      fail(new ServerFailure(cause.getMessage(), cause.getType(),
+          cause.getTrace()));
       return;
     }
-    processRelated(results.getRelated());
-
     // handle violations
     JsArray<DeltaValueStoreJsonImpl.ReturnRecord> violationsArray = results.getViolations();
     if (violationsArray != null) {
       processViolations(violationsArray);
     } else {
       deltaValueStore.commit(results.getSideEffects());
-      handleResult(results.getResult());
+      processRelated(results.getRelated());
+      if (results.isNullResult()) {
+        // Indicates the server explicitly meant to send a null value
+        succeed(null);
+      } else {
+        handleResult(results.getResult());
+      }
     }
   }
 
@@ -186,7 +206,7 @@
       } else {
         id = violationRecord.getEncodedId();
       }
-      final EntityProxyIdImpl key = new EntityProxyIdImpl(id,
+      final EntityProxyIdImpl<?> key = new EntityProxyIdImpl<EntityProxy>(id,
           requestFactory.getSchema(violationRecord.getSchema()),
           violationRecord.hasFutureId(), null);
       assert violationRecord.hasViolations();
@@ -206,7 +226,7 @@
             return path;
           }
 
-          public EntityProxyId getProxyId() {
+          public EntityProxyId<?> getProxyId() {
             return key;
           }
         });
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestFactoryEditorDriver.java b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestFactoryEditorDriver.java
index bd6ff87..ce47bb4 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestFactoryEditorDriver.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestFactoryEditorDriver.java
@@ -100,9 +100,8 @@
 
     traverseEditors(paths);
   }
-  
-  public void initialize(RequestFactory requestFactory,
-      E editor) {
+
+  public void initialize(RequestFactory requestFactory, E editor) {
     initialize(requestFactory.getEventBus(), requestFactory, editor);
   }
 
@@ -171,8 +170,7 @@
 
   private void checkSaveRequest() {
     if (saveRequest == null) {
-      throw new IllegalStateException(
-          "edit() was called with a null Request");
+      throw new IllegalStateException("edit() was called with a null Request");
     }
   }
 }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java
index 14252a5..17ab45a 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java
@@ -105,13 +105,13 @@
 
   private final RequestFactoryJsonImpl requestFactory;
   // track C-U-D of CRUD operations
-  private final Map<EntityProxyId, ProxyJsoImpl> creates = new HashMap<EntityProxyId, ProxyJsoImpl>();
+  private final Map<EntityProxyId<?>, ProxyJsoImpl> creates = new HashMap<EntityProxyId<?>, ProxyJsoImpl>();
 
-  private final Map<EntityProxyId, ProxyJsoImpl> updates = new HashMap<EntityProxyId, ProxyJsoImpl>();
+  private final Map<EntityProxyId<?>, ProxyJsoImpl> updates = new HashMap<EntityProxyId<?>, ProxyJsoImpl>();
   // nothing for deletes because DeltaValueStore is not involved in deletes. The
   // operation alone suffices.
 
-  private final Map<EntityProxyId, WriteOperation> operations = new HashMap<EntityProxyId, WriteOperation>();
+  private final Map<EntityProxyId<?>, WriteOperation> operations = new HashMap<EntityProxyId<?>, WriteOperation>();
 
   private boolean used = false;
 
@@ -136,17 +136,17 @@
       int length = newRecords.length();
       for (int i = 0; i < length; i++) {
         ReturnRecord newRecord = newRecords.get(i);
-        final EntityProxyIdImpl<?> futureKey = new EntityProxyIdImpl<EntityProxy>(
-            newRecord.getFutureId(),
-            requestFactory.getSchema(newRecord.getSchema()),
-            RequestFactoryJsonImpl.IS_FUTURE, null);
-        ProxyJsoImpl copy = ProxyJsoImpl.create(
-            newRecord.getFutureId(), 1, futureKey.schema,
-            requestFactory);
+        ProxySchema<?> schema = requestFactory.getSchema(newRecord.getSchema());
+        EntityProxyIdImpl<?> futureKey = new EntityProxyIdImpl<EntityProxy>(
+            newRecord.getFutureId(), schema, RequestFactoryJsonImpl.IS_FUTURE,
+            null);
+        ProxyJsoImpl copy = ProxyJsoImpl.create(newRecord.getFutureId(), 1,
+            schema, requestFactory);
         toRemove.add(futureKey);
         requestFactory.datastoreToFutureMap.put(newRecord.getEncodedId(),
             futureKey.schema, futureKey.encodedId);
-        requestFactory.futureToDatastoreMap.put(futureKey.encodedId, newRecord.getEncodedId());
+        requestFactory.futureToDatastoreMap.put(futureKey.encodedId,
+            newRecord.getEncodedId());
 
         /*
          * TODO (amitmanjhi): get all the data from the server. make a copy of
@@ -161,9 +161,7 @@
           copy.merge(value);
           copy.putEncodedId(newRecord.getEncodedId());
         }
-        ProxyJsoImpl masterRecord = master.records.get(futureKey);
-        assert masterRecord == null;
-        requestFactory.postChangeEvent(copy, WriteOperation.CREATE);
+        assert master.records.containsKey(futureKey);
       }
     }
     processToRemove(toRemove, WriteOperation.CREATE);
@@ -175,11 +173,11 @@
       int length = deletedRecords.length();
       for (int i = 0; i < length; i++) {
         ReturnRecord deletedRecord = deletedRecords.get(i);
-        final EntityProxyIdImpl key = getPersistedProxyId(
+        EntityProxyIdImpl<?> key = getPersistedProxyId(
             deletedRecord.getEncodedId(),
             requestFactory.getSchema(deletedRecord.getSchema()));
-        ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1, key.schema,
-            requestFactory);
+        ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1,
+            key.schema, requestFactory);
         requestFactory.postChangeEvent(copy, WriteOperation.DELETE);
         master.records.remove(key);
       }
@@ -191,10 +189,11 @@
       int length = updatedRecords.length();
       for (int i = 0; i < length; i++) {
         ReturnRecord updatedRecord = updatedRecords.get(i);
-        final EntityProxyIdImpl key = getPersistedProxyId(updatedRecord.getEncodedId(),
+        EntityProxyIdImpl<?> key = getPersistedProxyId(
+            updatedRecord.getEncodedId(),
             requestFactory.getSchema(updatedRecord.getSchema()));
-        ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1, key.schema,
-            requestFactory);
+        ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1,
+            key.schema, requestFactory);
         requestFactory.postChangeEvent(copy, WriteOperation.UPDATE);
         ProxyJsoImpl masterRecord = master.records.get(key);
         ProxyJsoImpl value = updates.get(key);
@@ -213,11 +212,37 @@
     processToRemove(toRemove, WriteOperation.UPDATE);
   }
 
+  public <V> V get(Property<V> property, EntityProxy record) {
+    ProxyJsoImpl proxy = creates.get(record.stableId());
+    if (proxy == null) {
+      proxy = updates.get(record.stableId());
+    }
+    if (proxy == null) {
+      return null;
+    }
+    return proxy.get(property);
+  }
+
   public boolean isChanged() {
     return !operations.isEmpty();
   }
 
   /**
+   * Returns <code>true</code> if a call to {@link #set} was made with the given
+   * property and record.
+   */
+  public <V> boolean isPropertySet(Property<V> property, EntityProxy record) {
+    ProxyJsoImpl proxy = creates.get(record.stableId());
+    if (proxy == null) {
+      proxy = updates.get(record.stableId());
+    }
+    if (proxy == null) {
+      return false;
+    }
+    return proxy.isDefined(property.getName());
+  }
+
+  /**
    * Reset the used flag. To be called only when an unsuccessful reponse has
    * been received after a {@link #toJson()} string has been sent to the server.
    */
@@ -230,6 +255,8 @@
     ProxyImpl recordImpl = (ProxyImpl) record;
     EntityProxyId<?> recordKey = recordImpl.stableId();
 
+    retainValue(value);
+
     ProxyJsoImpl rawMasterRecord = master.records.get(recordKey);
     WriteOperation priorOperation = operations.get(recordKey);
     if (rawMasterRecord == null && priorOperation == null) {
@@ -277,13 +304,49 @@
   }
 
   /**
-   * Has side effect of setting the used flag, meaning further 
-   * sets will fail until clearUsed is called. Cannot be called
-   * while used.
+   * Clean-up logic to ensure that any values referenced in the payload will be
+   * transmitted to the server. Specifically, this ensures that all referenced,
+   * future ProxyImpls will be transmitted to the server, even if they have no
+   * associated property changes.
+   */
+  void retainValue(Object value) {
+    if (value instanceof Iterable<?>) {
+      // Retain values in collections
+      for (Object o : (Iterable<?>) value) {
+        retainValue(o);
+        return;
+      }
+    }
+
+    if (!(value instanceof ProxyImpl)) {
+      // Ignore anything that's not a proxy
+      return;
+    }
+
+    ProxyImpl proxy = (ProxyImpl) value;
+    if (!proxy.unpersisted()) {
+      // A persisted proxy doesn't need to be retained
+      return;
+    }
+
+    EntityProxyId<?> id = proxy.stableId();
+    if (operations.containsKey(id)) {
+      // Already retained
+      return;
+    }
+
+    // Retain
+    creates.put(id, proxy.asJso());
+    operations.put(id, WriteOperation.CREATE);
+  }
+
+  /**
+   * Has side effect of setting the used flag, meaning further sets will fail
+   * until clearUsed is called. Cannot be called while used.
    */
   String toJson() {
     assertNotUsed();
-    
+
     used = true;
     StringBuffer jsonData = new StringBuffer("{");
     for (WriteOperation writeOperation : new WriteOperation[] {
@@ -304,14 +367,19 @@
   /**
    * returns true if a new change record has been added.
    */
-  private <V> boolean addNewChangeRecord(EntityProxyId recordKey,
+  private <V> boolean addNewChangeRecord(EntityProxyId<?> recordKey,
       ProxyImpl recordImpl, Property<V> property, V value) {
     ProxyJsoImpl rawMasterRecord = master.records.get(recordKey);
     ProxyJsoImpl changeRecord = newChangeRecord(recordImpl);
     if (isRealChange(property, value, rawMasterRecord)) {
       changeRecord.set(property, value);
-      updates.put(recordKey, changeRecord);
-      operations.put(recordKey, WriteOperation.UPDATE);
+      if (recordImpl.unpersisted()) {
+        creates.put(recordKey, changeRecord);
+        operations.put(recordKey, WriteOperation.CREATE);
+      } else {
+        updates.put(recordKey, changeRecord);
+        operations.put(recordKey, WriteOperation.UPDATE);
+      }
       return true;
     }
     return false;
@@ -326,7 +394,7 @@
 
   private void assertNotUsedAndCorrectType(EntityProxy record) {
     assertNotUsed();
-    
+
     if (!(record instanceof ProxyImpl)) {
       throw new IllegalArgumentException(record + " + must be an instance of "
           + ProxyImpl.class);
@@ -335,22 +403,22 @@
 
   private String getJsonForOperation(WriteOperation writeOperation) {
     assert (writeOperation == WriteOperation.CREATE || writeOperation == WriteOperation.UPDATE);
-    Map<EntityProxyId, ProxyJsoImpl> recordsMap = getRecordsMap(writeOperation);
+    Map<EntityProxyId<?>, ProxyJsoImpl> recordsMap = getRecordsMap(writeOperation);
     if (recordsMap.size() == 0) {
       return "";
     }
-    StringBuffer requestData = new StringBuffer("\"" + writeOperation.getUnObfuscatedEnumName()
-        + "\":[");
+    StringBuffer requestData = new StringBuffer("\""
+        + writeOperation.getUnObfuscatedEnumName() + "\":[");
     boolean first = true;
-    for (Map.Entry<EntityProxyId, ProxyJsoImpl> entry : recordsMap.entrySet()) {
+    for (Map.Entry<EntityProxyId<?>, ProxyJsoImpl> entry : recordsMap.entrySet()) {
       ProxyJsoImpl impl = entry.getValue();
       if (first) {
         first = false;
       } else {
         requestData.append(",");
       }
-      requestData.append("{\""
-          + entry.getValue().getSchema().getToken() + "\":");
+      requestData.append("{\"" + entry.getValue().getSchema().getToken()
+          + "\":");
       requestData.append(impl.toJson());
       requestData.append("}");
     }
@@ -358,14 +426,14 @@
     return requestData.toString();
   }
 
-  private EntityProxyIdImpl getPersistedProxyId(String encodedId,
+  private EntityProxyIdImpl<?> getPersistedProxyId(String encodedId,
       ProxySchema<?> schema) {
-    return new EntityProxyIdImpl(encodedId, schema,
+    return new EntityProxyIdImpl<EntityProxy>(encodedId, schema,
         RequestFactoryJsonImpl.NOT_FUTURE,
         requestFactory.datastoreToFutureMap.get(encodedId, schema));
   }
 
-  private Map<EntityProxyId, ProxyJsoImpl> getRecordsMap(
+  private Map<EntityProxyId<?>, ProxyJsoImpl> getRecordsMap(
       WriteOperation writeOperation) {
     switch (writeOperation) {
       case CREATE:
@@ -386,10 +454,10 @@
       return true;
     }
 
-    if (property instanceof CollectionProperty) {
+    if (property instanceof CollectionProperty<?, ?>) {
       return true;
     }
-    
+
     masterRecord = rawMasterRecord.cast();
 
     if (!masterRecord.isDefined(property.getName())) {
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/JsoCollection.java b/user/src/com/google/gwt/requestfactory/client/impl/JsoCollection.java
index 3c89f2f..4196c8b 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/JsoCollection.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/JsoCollection.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2010 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -26,12 +26,11 @@
   /**
    * Inject dependencies needed by jso collections to commit mutations to
    * {@link DeltaValueStoreJsonImpl}.
-   * @param dvs DeltaValueStoreImpl obtained by editing a Proxy
+   * 
    * @param property the Property corresponding to the contained type
    * @param proxy the Proxy on which this collection resides
    */
-  void setDependencies(DeltaValueStoreJsonImpl dvs, Property property,
-      ProxyImpl proxy);
+  void setDependencies(Property<?> property, ProxyImpl proxy);
 
   /**
    * Returns the JavaScriptObject (usually a raw JS Array) backing this
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/JsoList.java b/user/src/com/google/gwt/requestfactory/client/impl/JsoList.java
index 5cc62a8..60b8829 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/JsoList.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/JsoList.java
@@ -41,9 +41,7 @@
 
   private final JavaScriptObject array;
 
-  private DeltaValueStoreJsonImpl deltaValueStore;
-
-  private CollectionProperty property;
+  private CollectionProperty<JsoList<T>, T> property;
 
   private ProxyImpl record;
 
@@ -69,10 +67,17 @@
     return array;
   }
 
+  /**
+   * Ensures that any EntityProxy returned is mutable if the enclosing proxy
+   * is mutable.
+   */
   @Override
-  @SuppressWarnings("unchecked")
   public T get(int i) {
-    return get0(i);
+    T toReturn = get0(i);
+    if (record.mutable()) {
+      toReturn = record.request().ensureMutable(toReturn);
+    }
+    return toReturn;
   }
 
   @SuppressWarnings("unchecked")
@@ -190,10 +195,9 @@
     return old;
   }
 
-  public void setDependencies(DeltaValueStoreJsonImpl dvs, Property property,
-      ProxyImpl proxy) {
-    this.deltaValueStore = dvs;
-    this.property = (CollectionProperty) property;
+  @SuppressWarnings("unchecked")
+  public void setDependencies(Property<?> property, ProxyImpl proxy) {
+    this.property = (CollectionProperty<JsoList<T>, T>) property;
     this.record = proxy;
   }
 
@@ -203,8 +207,8 @@
   }
 
   private void dvsUpdate() {
-    if (deltaValueStore != null) {
-      deltaValueStore.set(property, record, this);
+    if (record.mutable()) {
+      record.<JsoList<T>> set(property, record, this);
     }
   }
 
@@ -212,11 +216,12 @@
         return jso[i];
     }-*/;
 
+  @SuppressWarnings("unchecked")
   private T get0(int i) {
     if (TypeLibrary.isProxyType(property.getLeafType())) {
       String key[] = ((JsArrayString) array).get(i).split("@", 3);
-      return (T) rf.getValueStore().getRecordBySchemaAndId(rf.getSchema(key[2]),
-          key[0], rf);
+      return (T) rf.getValueStore().getRecordBySchemaAndId(
+          rf.getSchema(key[2]), key[0], "IS".equals(key[1]), rf);
     } else {
       return (T) get(array, i, property.getLeafType());
     }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/JsoSet.java b/user/src/com/google/gwt/requestfactory/client/impl/JsoSet.java
index 424c066..dd804ad 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/JsoSet.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/JsoSet.java
@@ -90,10 +90,9 @@
     return false;
   }
 
-  public void setDependencies(DeltaValueStoreJsonImpl dvs, Property property,
-      ProxyImpl proxy) {
+  public void setDependencies(Property<?> property, ProxyImpl proxy) {
     list = new JsoList<T>(rf, array);
-    list.setDependencies(dvs, property, proxy);
+    list.setDependencies(property, proxy);
     for (T t : list) {
       set.add(key(t));
     }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java b/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java
index ccc18a8..5030427 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java
@@ -51,4 +51,11 @@
   final native JsArray<DeltaValueStoreJsonImpl.ReturnRecord> getViolations()/*-{
     return this.violations || null;
   }-*/;
+  
+  /**
+   * Looks for an explicit <code>{result: null}</code> in the payload.
+   */
+  final native boolean isNullResult() /*-{
+    return this.result === null;
+  }-*/;
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
index 13a4c65..c7062fd 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
@@ -43,9 +43,9 @@
 
   private final ProxyJsoImpl jso;
   private final boolean isFuture;
-
   private DeltaValueStoreJsonImpl deltaValueStore;
-  
+  private AbstractRequest<?, ?> request;
+
   /**
    * For use by generated subclasses only. Other code should use
    * {@link ProxySchema#create(ProxyJsoImpl, boolean)}, typically:
@@ -61,7 +61,6 @@
     assert jso.getSchema() != null;
     this.jso = jso;
     this.isFuture = isFuture;
-    deltaValueStore = null;
   }
 
   public ProxyJsoImpl asJso() {
@@ -73,10 +72,28 @@
   }
 
   /**
-   * Get this proxy's value for the given property. Behavior is undefined if
-   * the proxy has no such property, or if the property has never been set. It
-   * is unusual to call this method directly. Rather it is expected to be called
-   * by bean-style getter methods provided by implementing classes.
+   * A ProxyImpl is equal to another ProxyImpl if they have equal EntityProxyIds
+   * and they are from the same Request object.
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof ProxyImpl)) {
+      return false;
+    }
+    ProxyImpl other = (ProxyImpl) o;
+    return stableId().equals(other.stableId())
+        && (request == other.request || request != null
+            && request.equals(other.request));
+  }
+
+  /**
+   * Get this proxy's value for the given property. Behavior is undefined if the
+   * proxy has no such property, or if the property has never been set. It is
+   * unusual to call this method directly. Rather it is expected to be called by
+   * bean-style getter methods provided by implementing classes.
+   * <p>
+   * If the ProxyImpl is mutable, any EntityProxies reachable from the return
+   * value will have already been made mutable.
    * 
    * @param <V> the type of the property's value
    * @param property the property to fetch
@@ -84,17 +101,29 @@
    */
   @SuppressWarnings("unchecked")
   public <V> V get(Property<V> property) {
-    if (property instanceof CollectionProperty) {
-      V toReturn = (V) jso.getCollection((CollectionProperty) property);
-      if (toReturn != null) {
-        ((JsoCollection) toReturn).setDependencies(deltaValueStore, property,
-            this);
+    // Read through to the DeltaValueStore to see if the entity has been mutated
+    V toReturn = null;
+    if (deltaValueStore != null
+        && deltaValueStore.isPropertySet(property, this)) {
+      toReturn = deltaValueStore.get(property, this);
+    } else {
+      if (property instanceof CollectionProperty) {
+        // Possibly create a new JsoCollection if one does not exist
+        toReturn = (V) jso.getCollection((CollectionProperty) property);
+      } else {
+        // Return a scalar property from the backing object
+        toReturn = jso.<V> get(property);
       }
-      return toReturn;
     }
-    return jso.<V> get(property);
+    // Ensure mutability
+    if (toReturn instanceof JsoCollection) {
+      ((JsoCollection) toReturn).setDependencies(property, this);
+    } else if (mutable()) {
+      toReturn = request.ensureMutable(toReturn);
+    }
+    return toReturn;
   }
-  
+
   public <V> V get(String propertyName, Class<?> propertyType) {
     // javac 1.6.0_20 on mac has problems without the explicit parameterization
     return jso.<V> get(propertyName, propertyType);
@@ -107,6 +136,20 @@
     return deltaValueStore.isChanged();
   }
 
+  @Override
+  public int hashCode() {
+    return stableId().hashCode() * 13
+        + (request == null ? 0 : request.hashCode()) * 5;
+  }
+
+  public boolean mutable() {
+    return deltaValueStore != null;
+  }
+
+  public AbstractRequest<?, ?> request() {
+    return request;
+  }
+
   public ProxySchema<?> schema() {
     return jso.getSchema();
   }
@@ -119,17 +162,17 @@
     deltaValueStore.set(property, record, value);
   }
 
-  // Allow the generated subclass to return the specific type its public interface probably demands
-  @SuppressWarnings({"unchecked", "rawtypes"})
+  /**
+   * Allow the generated subclass to return the specific type its public
+   * interface probably demands.
+   */
+  @SuppressWarnings(value = {"unchecked", "rawtypes"})
   public EntityProxyId stableId() {
-    if (!isFuture) {
-      return new EntityProxyIdImpl<ProxyImpl>(
-          encodedId(),
-          schema(),
-          false,
-          jso.getRequestFactory().datastoreToFutureMap.get(encodedId(), schema()));
+    if (isFuture) {
+      return new EntityProxyIdImpl(encodedId(), schema(), isFuture, null);
     }
-    return new EntityProxyIdImpl(encodedId(), schema(), isFuture, null);
+    return new EntityProxyIdImpl<ProxyImpl>(encodedId(), schema(), false,
+        jso.getRequestFactory().datastoreToFutureMap.get(encodedId(), schema()));
   }
 
   public boolean unpersisted() {
@@ -147,8 +190,10 @@
   protected ValueStoreJsonImpl valueStore() {
     return jso.getRequestFactory().getValueStore();
   }
-  
-  void putDeltaValueStore(DeltaValueStoreJsonImpl deltaValueStore) {
+
+  void putDeltaValueStore(DeltaValueStoreJsonImpl deltaValueStore,
+      AbstractRequest<?, ?> request) {
     this.deltaValueStore = deltaValueStore;
+    this.request = request;
   }
 }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java
index f7c9520..7f66fba 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java
@@ -154,7 +154,7 @@
       assert type == List.class || type == Set.class;
       JsoCollection col = (JsoCollection) getCollection(
           (CollectionProperty) property);
-      col.setDependencies(null, property, null);
+      col.setDependencies(property, null);
       return (V) col;
     }
     // javac 1.6.0_20 on mac has problems without the explicit parameterization
@@ -246,8 +246,9 @@
       String schemaAndId[] = relatedId.split("@");
       assert schemaAndId.length == 3;
       ProxySchema<?> schema = getRequestFactory().getSchema(schemaAndId[2]);
-      return (V) getRequestFactory().getValueStore().getRecordBySchemaAndId(schema,
-          schemaAndId[0], getRequestFactory());
+      EntityProxy toReturn = getRequestFactory().getValueStore().getRecordBySchemaAndId(schema,
+          schemaAndId[0], schemaAndId[1].equals("IS"), getRequestFactory());
+      return (V) toReturn;
     }
   }                                                                                                 
 
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java
index 56c346c..8229081 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java
@@ -46,17 +46,15 @@
 
     public void onProxyChange(EntityProxyChange<EntityProxy> event) {
       if (event.getWriteOperation().equals(WriteOperation.UPDATE)
-          && event.getProxyId().equals(
-              ((EntityProxy) getObject()).stableId())) {
+          && event.getProxyId().equals(((EntityProxy) getObject()).stableId())) {
         List<String> paths = new ArrayList<String>();
         traverse(paths);
-        @SuppressWarnings("rawtypes")
-        EntityProxyId id = event.getProxyId();
+        EntityProxyId<?> id = event.getProxyId();
         doFind(paths, id);
       }
     }
 
-    @SuppressWarnings({"rawtypes", "unchecked"})
+    @SuppressWarnings( {"rawtypes", "unchecked"})
     private void doFind(List<String> paths, EntityProxyId id) {
       factory.find(id).with(paths.toArray(new String[paths.size()])).fire(
           new SubscriptionReceiver());
@@ -76,20 +74,6 @@
   protected RequestFactory factory;
   protected Request<?> request;
 
-  @Override
-  public P ensureMutable(P object) {
-    if (request == null) {
-      throw new IllegalStateException("No Request");
-    } else if (object instanceof EntityProxy) {
-      @SuppressWarnings("unchecked")
-      P toReturn = (P) request.edit(((EntityProxy) object));
-      return toReturn;
-    } else {
-      // Likely a value object
-      return object;
-    }
-  }
-
   public void initialize(EventBus eventBus, RequestFactory factory,
       String pathSoFar, P object, E editor, DelegateMap delegateMap,
       Request<?> editRequest) {
@@ -120,6 +104,15 @@
   }
 
   @Override
+  protected <T> T ensureMutable(T object) {
+    if (request == null) {
+      // Read-only mode
+      return object;
+    }
+    return ((AbstractRequest<?, ?>) request).<T> ensureMutable(object);
+  }
+
+  @Override
   protected <R, S extends Editor<R>> void initializeSubDelegate(
       AbstractEditorDelegate<R, S> subDelegate, String path, R object,
       S subEditor, DelegateMap delegateMap) {
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
index 8a92f1f..f6758f2 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
@@ -112,6 +112,15 @@
   public void fire(Request<?> requestObject) {
     final AbstractRequest<?, ?> abstractRequest = (AbstractRequest<?, ?>) requestObject;
     RequestData requestData = ((AbstractRequest<?, ?>) requestObject).getRequestData();
+
+    /*
+     * Prevent the "dummy object" case for parameters with no associated
+     * property updates.
+     */
+    for (Object proxy : requestData.getProxyParameters()) {
+      abstractRequest.deltaValueStore.retainValue(proxy);
+    }
+
     Map<String, String> requestMap = requestData.getRequestMap(abstractRequest.deltaValueStore.toJson());
 
     String payload = ClientRequestHelper.getRequestString(requestMap);
@@ -240,6 +249,10 @@
   }
 
   ValueStoreJsonImpl getValueStore() {
+    if (valueStore == null) {
+      throw new IllegalStateException(
+          "must call RequestFactory.initialize() first");
+    }
     return valueStore;
   }
 
@@ -263,6 +276,9 @@
     Long futureId = ++currentFutureId;
     ProxyJsoImpl newRecord = ProxyJsoImpl.create(Long.toString(futureId),
         initialVersion, schema, this);
-    return schema.create(newRecord, IS_FUTURE);
+    R created = schema.create(newRecord, IS_FUTURE);
+    // Need to be able to find the future object to hook up future-to-future ref
+    getValueStore().putFutureInValueStore(newRecord);
+    return created;
   }
 }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java
index 07fe41b..ffa3572 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java
@@ -32,17 +32,30 @@
 class ValueStoreJsonImpl {
   // package protected fields for use by DeltaValueStoreJsonImpl
 
-  final Map<EntityProxyIdImpl, ProxyJsoImpl> records = new HashMap<EntityProxyIdImpl, ProxyJsoImpl>();
+  final Map<EntityProxyIdImpl<?>, ProxyJsoImpl> records = new HashMap<EntityProxyIdImpl<?>, ProxyJsoImpl>();
 
   EntityProxy getRecordBySchemaAndId(ProxySchema<?> schema, String encodedId,
-      RequestFactoryJsonImpl requestFactory) {
+      boolean isFuture, RequestFactoryJsonImpl requestFactory) {
     if (encodedId == null) {
       return null;
     }
-    // TODO: pass isFuture to this method from decoding ID string
-    EntityProxyIdImpl key = new EntityProxyIdImpl(encodedId, schema, false,
-        requestFactory.datastoreToFutureMap.get(encodedId, schema));
-    return schema.create(records.get(key));
+
+    EntityProxyIdImpl<?> key = new EntityProxyIdImpl<EntityProxy>(encodedId,
+        schema, isFuture, requestFactory.datastoreToFutureMap.get(encodedId,
+            schema));
+    return schema.create(records.get(key), isFuture);
+  }
+
+  /**
+   * Puts a newly-created {@link ProxyJsoImpl} newJsoRecord in the valueStore
+   * following a create, and sends appropriate events. If the valuestore had a
+   * Jso that was the same or a superset of newJsoRecord, returns the valuestore
+   * jso. Otherwise, puts newJsoRecord in the valuestore and returns null.
+   * <p>
+   * package-protected for testing purposes.
+   */
+  ProxyJsoImpl putFutureInValueStore(ProxyJsoImpl newJsoRecord) {
+    return putInValueStore(newJsoRecord, RequestFactoryJsonImpl.IS_FUTURE);
   }
 
   /**
@@ -54,26 +67,7 @@
    * package-protected for testing purposes.
    */
   ProxyJsoImpl putInValueStore(ProxyJsoImpl newJsoRecord) {
-    EntityProxyIdImpl recordKey = new EntityProxyIdImpl(newJsoRecord.encodedId(),
-        newJsoRecord.getSchema(), RequestFactoryJsonImpl.NOT_FUTURE,
-        newJsoRecord.getRequestFactory().datastoreToFutureMap.get(
-            newJsoRecord.encodedId(), newJsoRecord.getSchema()));
-
-    ProxyJsoImpl oldRecord = records.get(recordKey);
-    if (oldRecord == null) {
-      records.put(recordKey, newJsoRecord);
-      newJsoRecord.assertValid();
-      newJsoRecord.getRequestFactory().postChangeEvent(newJsoRecord,
-          WriteOperation.ACQUIRE);
-      return null;
-    }
-    if (oldRecord.hasChanged(newJsoRecord)) {
-      records.put(recordKey, newJsoRecord);
-      newJsoRecord.getRequestFactory().postChangeEvent(newJsoRecord,
-          WriteOperation.UPDATE);
-      return null;
-    }
-    return oldRecord;
+    return putInValueStore(newJsoRecord, RequestFactoryJsonImpl.NOT_FUTURE);
   }
 
   void setRecords(JsArray<ProxyJsoImpl> newRecords) {
@@ -84,4 +78,29 @@
       }
     }
   }
+
+  private ProxyJsoImpl putInValueStore(ProxyJsoImpl newJsoRecord,
+      boolean isFuture) {
+    RequestFactoryJsonImpl factory = newJsoRecord.getRequestFactory();
+    EntityProxyIdImpl<?> recordKey = new EntityProxyIdImpl<EntityProxy>(
+        newJsoRecord.encodedId(), newJsoRecord.getSchema(), isFuture,
+        factory.datastoreToFutureMap.get(newJsoRecord.encodedId(),
+            newJsoRecord.getSchema()));
+
+    ProxyJsoImpl oldRecord = records.get(recordKey);
+    if (oldRecord == null) {
+      records.put(recordKey, newJsoRecord);
+      newJsoRecord.assertValid();
+      factory.postChangeEvent(newJsoRecord, isFuture ? WriteOperation.CREATE
+          : WriteOperation.ACQUIRE);
+      return null;
+    } 
+
+    if (oldRecord.hasChanged(newJsoRecord)) {
+      records.put(recordKey, newJsoRecord);
+      factory.postChangeEvent(newJsoRecord, WriteOperation.UPDATE);
+      return null;
+    }
+    return oldRecord;
+  }
 }
diff --git a/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java b/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
index 75e75db..76483ed 100644
--- a/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
+++ b/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
@@ -92,17 +92,16 @@
  */
 public class RequestFactoryGenerator extends Generator {
 
-  private enum CollectionType { 
-    SCALAR("ObjectRequestImpl", AbstractJsonObjectRequest.class),
-    LIST("ListRequestImpl", AbstractJsonProxyListRequest.class),
-    SET("SetRequestImpl", AbstractJsonProxySetRequest.class);
+  private enum CollectionType {
+    SCALAR("ObjectRequestImpl", AbstractJsonObjectRequest.class), LIST(
+        "ListRequestImpl", AbstractJsonProxyListRequest.class), SET(
+        "SetRequestImpl", AbstractJsonProxySetRequest.class);
 
     private String implName;
 
     private Class<?> requestClass;
 
-    CollectionType(String implName,
-        Class<?> requestClass) {
+    CollectionType(String implName, Class<?> requestClass) {
       this.implName = implName;
       this.requestClass = requestClass;
     }
@@ -149,7 +148,7 @@
     listType = typeOracle.findType(List.class.getName());
     setType = typeOracle.findType(Set.class.getName());
     entityProxyType = typeOracle.findType(EntityProxy.class.getName());
-    
+
     // Get a reference to the type that the generator should implement
     JClassType interfaceType = typeOracle.findType(interfaceName);
 
@@ -208,7 +207,8 @@
         continue;
       }
 
-      EntityProperty entityProperty = maybeComputePropertyFromMethod(method, logger);
+      EntityProperty entityProperty = maybeComputePropertyFromMethod(method,
+          logger);
       if (entityProperty != null) {
         String propertyName = entityProperty.getName();
         if (!propertyNames.contains(propertyName)) {
@@ -220,7 +220,7 @@
 
     return entityProperties;
   };
-  
+
   private void ensureProxyType(TreeLogger logger,
       GeneratorContext generatorContext, JClassType publicProxyType)
       throws UnableToCompleteException {
@@ -245,21 +245,21 @@
     Set<JClassType> transitiveDeps = new LinkedHashSet<JClassType>();
 
     if (pw != null) {
-      logger = logger.branch(TreeLogger.DEBUG,
-          "Generating " + publicProxyType.getName());
+      logger = logger.branch(TreeLogger.DEBUG, "Generating "
+          + publicProxyType.getName());
 
       ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
           packageName, proxyImplTypeName);
 
-      f.addImport(AbstractJsonProxySetRequest.class.getName());  
+      f.addImport(AbstractJsonProxySetRequest.class.getName());
       f.addImport(AbstractJsonProxyListRequest.class.getName());
-      f.addImport(AbstractJsonValueListRequest.class.getName());      
+      f.addImport(AbstractJsonValueListRequest.class.getName());
       f.addImport(AbstractJsonObjectRequest.class.getName());
       f.addImport(RequestFactoryJsonImpl.class.getName());
       f.addImport(Property.class.getName());
       f.addImport(EnumProperty.class.getName());
       f.addImport(CollectionProperty.class.getName());
-      
+
       f.addImport(EntityProxy.class.getName());
       f.addImport(ProxyImpl.class.getName());
       f.addImport(ProxyJsoImpl.class.getName());
@@ -273,7 +273,8 @@
       f.setSuperclass(ProxyImpl.class.getSimpleName());
       f.addImplementedInterface(publicProxyType.getName());
 
-      List<EntityProperty> entityProperties = computeEntityPropertiesFromProxyType(publicProxyType, logger);
+      List<EntityProperty> entityProperties = computeEntityPropertiesFromProxyType(
+          publicProxyType, logger);
       for (EntityProperty entityProperty : entityProperties) {
         JType type = entityProperty.getType();
         if (type.isPrimitive() == null) {
@@ -291,15 +292,13 @@
         if (entityProperty.getType().isEnum() != null) {
           sw.println(String.format(
               "private static final Property<%1$s> %2$s = new EnumProperty<%1$s>(\"%2$s\", %1$s.class, %1$s.values());",
-              entityProperty.getType().getSimpleSourceName(),
-              name));
+              entityProperty.getType().getSimpleSourceName(), name));
         } else if (isCollection(typeOracle, entityProperty.getType())) {
           sw.println(String.format(
               "private static final Property<%1$s> %2$s = new CollectionProperty<%1$s, %3$s>(\"%2$s\", %1$s.class, %3$s.class);",
               entityProperty.getType().getSimpleSourceName(),
               name,
-              entityProperty.getType().isParameterized().getTypeArgs()[0].getQualifiedSourceName()
-              ));
+              entityProperty.getType().isParameterized().getTypeArgs()[0].getQualifiedSourceName()));
         } else {
           sw.println(String.format(
               "private static final Property<%1$s> %2$s = new Property<%1$s>(\"%2$s\", \"%3$s\", %1$s.class);",
@@ -312,9 +311,12 @@
 
       sw.println();
       String simpleImplName = publicProxyType.getSimpleSourceName() + "Impl";
-      printRequestImplClass(sw, publicProxyType, simpleImplName, CollectionType.LIST);
-      printRequestImplClass(sw, publicProxyType, simpleImplName, CollectionType.SET);
-      printRequestImplClass(sw, publicProxyType, simpleImplName, CollectionType.SCALAR);
+      printRequestImplClass(sw, publicProxyType, simpleImplName,
+          CollectionType.LIST);
+      printRequestImplClass(sw, publicProxyType, simpleImplName,
+          CollectionType.SET);
+      printRequestImplClass(sw, publicProxyType, simpleImplName,
+          CollectionType.SCALAR);
 
       sw.println();
       sw.println(String.format(
@@ -336,13 +338,12 @@
         JClassType collectionType = returnType.isClassOrInterface();
 
         if (collectionType != null && collectionType.isParameterized() != null) {
-           returnType = collectionType.isParameterized().getTypeArgs()[0];
-           returnTypeString = collectionType.isParameterized().getParameterizedQualifiedSourceName();
+          returnType = collectionType.isParameterized().getTypeArgs()[0];
+          returnTypeString = collectionType.isParameterized().getParameterizedQualifiedSourceName();
         }
 
         sw.println();
-        sw.println(String.format("public %s get%s() {",
-            returnTypeString,
+        sw.println(String.format("public %s get%s() {", returnTypeString,
             capitalize(entityProperty.getName())));
         sw.indent();
         sw.println(String.format("return get(%s);", entityProperty.getName()));
@@ -383,10 +384,8 @@
       JClassType interfaceType, String packageName, String implName)
       throws UnableToCompleteException {
 
-    logger = logger.branch(
-        TreeLogger.DEBUG,
-        String.format("Generating implementation of %s",
-            interfaceType.getName()));
+    logger = logger.branch(TreeLogger.DEBUG, String.format(
+        "Generating implementation of %s", interfaceType.getName()));
 
     ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
         packageName, implName);
@@ -414,8 +413,10 @@
       }
       JType returnType = method.getReturnType();
       if (null == returnType) {
-        logger.log(TreeLogger.ERROR, String.format(
-            "Illegal return type for %s. Methods of %s must return interfaces, found void",
+        logger.log(
+            TreeLogger.ERROR,
+            String.format(
+                "Illegal return type for %s. Methods of %s must return interfaces, found void",
                 method.getName(), interfaceType.getName()));
         throw new UnableToCompleteException();
       }
@@ -428,7 +429,7 @@
       }
       requestBuilders.add(method);
     }
-    
+
     /*
      * Hard-code the requestSelectors specified in RequestFactory.
      */
@@ -461,11 +462,12 @@
     sw.outdent();
     sw.println("}");
     sw.println();
-    
+
     // write getHistoryToken(proxyId)
     sw.println("public String getHistoryToken(EntityProxyId proxyId) {");
     sw.indent();
-    sw.println("return getHistoryToken(proxyId, new " + proxyToTypeMapName + "());");
+    sw.println("return getHistoryToken(proxyId, new " + proxyToTypeMapName
+        + "());");
     sw.outdent();
     sw.println("}");
     sw.println();
@@ -537,10 +539,8 @@
   private void generateProxyToTypeMap(TreeLogger logger,
       GeneratorContext generatorContext, PrintWriter out,
       JClassType interfaceType, String packageName, String implName) {
-    logger = logger.branch(
-        TreeLogger.DEBUG,
-        String.format("Generating implementation of %s",
-            interfaceType.getName()));
+    logger = logger.branch(TreeLogger.DEBUG, String.format(
+        "Generating implementation of %s", interfaceType.getName()));
 
     ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
         packageName, implName);
@@ -616,10 +616,8 @@
       JMethod selectorMethod, JClassType mainType, String packageName,
       String implName) throws UnableToCompleteException {
     JClassType selectorInterface = selectorMethod.getReturnType().isInterface();
-    logger = logger.branch(
-        TreeLogger.DEBUG,
-        String.format("Generating implementation of %s",
-            selectorInterface.getName()));
+    logger = logger.branch(TreeLogger.DEBUG, String.format(
+        "Generating implementation of %s", selectorInterface.getName()));
 
     ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
         packageName, implName);
@@ -643,12 +641,13 @@
 
     // write each method.
     for (JMethod method : selectorInterface.getOverridableMethods()) {
-      JParameterizedType parameterizedType = method.getReturnType()
-          .isParameterized();
+      JParameterizedType parameterizedType = method.getReturnType().isParameterized();
       if (parameterizedType == null) {
-        logger.log(TreeLogger.ERROR, String.format(
-            "Illegal return type for %s. Methods of %s must return Request<T>.",
-            method.getName(), selectorInterface.getName()));
+        logger.log(
+            TreeLogger.ERROR,
+            String.format(
+                "Illegal return type for %s. Methods of %s must return Request<T>.",
+                method.getName(), selectorInterface.getName()));
         throw new UnableToCompleteException();
       }
       JClassType returnType = parameterizedType.getTypeArgs()[0];
@@ -673,17 +672,20 @@
       }
       for (JParameter param : method.getParameters()) {
         if (param.getType().isArray() != null) {
-          logger.log(TreeLogger.ERROR, String.format(
-            "Illegal param type %s for %s. Methods of %s cannot take array parameters.",
-            param.getName(), method.getName(), selectorInterface.getName()));
+          logger.log(
+              TreeLogger.ERROR,
+              String.format(
+                  "Illegal param type %s for %s. Methods of %s cannot take array parameters.",
+                  param.getName(), method.getName(),
+                  selectorInterface.getName()));
           throw new UnableToCompleteException();
         }
       }
       if (isProxyCollectionRequest(typeOracle, requestType)) {
         Class<?> colType = getCollectionType(typeOracle, requestType);
         assert colType != null;
-        requestClassName = asInnerImplClass(colType == List.class ?
-            "ListRequestImpl" : "SetRequestImpl", returnType);
+        requestClassName = asInnerImplClass(colType == List.class
+            ? "ListRequestImpl" : "SetRequestImpl", returnType);
       } else if (isProxyRequest(typeOracle, requestType)) {
         if (selectorInterface.isAssignableTo(typeOracle.findType(FindRequest.class.getName()))) {
           extraArgs = ", proxyId";
@@ -692,17 +694,17 @@
           requestClassName = asInnerImplClass("ObjectRequestImpl", returnType);
         }
       } else if (isValueListRequest(typeOracle, requestType)) {
-         requestClassName = AbstractJsonValueListRequest.class.getName();
-         // generate argument list for AbstractJsonValueListRequest constructor
-         JClassType colType = requestType.isParameterized().getTypeArgs()[0];
-         extraArgs = ", " + colType.isAssignableTo(setType);
-         // extraArgs = ", isSet"  true if elementType of collection is Set
-         JClassType leafType = colType.isParameterized().getTypeArgs()[0];
-         extraArgs += ", " + leafType.getQualifiedSourceName() + ".class";
-         // extraArgs = ", isSet, collectionElementType.class"
+        requestClassName = AbstractJsonValueListRequest.class.getName();
+        // generate argument list for AbstractJsonValueListRequest constructor
+        JClassType colType = requestType.isParameterized().getTypeArgs()[0];
+        extraArgs = ", " + colType.isAssignableTo(setType);
+        // extraArgs = ", isSet" true if elementType of collection is Set
+        JClassType leafType = colType.isParameterized().getTypeArgs()[0];
+        extraArgs += ", " + leafType.getQualifiedSourceName() + ".class";
+        // extraArgs = ", isSet, collectionElementType.class"
         if (leafType.isAssignableTo(typeOracle.findType(Enum.class.getName()))) {
           // if contained type is Enum, pass Enum.values()
-          extraArgs += ", " + leafType.getQualifiedSourceName() + ".values()"; 
+          extraArgs += ", " + leafType.getQualifiedSourceName() + ".values()";
         } else {
           // else for all other types, pass null
           extraArgs += ", null";
@@ -734,8 +736,7 @@
       } else if (isEnumRequest(typeOracle, requestType)) {
         requestClassName = AbstractEnumRequest.class.getName();
         JClassType enumType = requestType.isParameterized().getTypeArgs()[0];
-        extraArgs = ", " + enumType.getQualifiedSourceName()
-            + ".values()";
+        extraArgs = ", " + enumType.getQualifiedSourceName() + ".values()";
       } else if (isVoidRequest(typeOracle, requestType)) {
         requestClassName = AbstractVoidRequest.class.getName();
       } else {
@@ -746,15 +747,16 @@
 
       sw.println(getMethodDeclaration(method) + " {");
       sw.indent();
-      sw.println(
-          "return new " + requestClassName + "(factory" + extraArgs + ") {");
+      sw.println("return new " + requestClassName + "(factory" + extraArgs
+          + ") {");
       sw.indent();
       String requestDataName = RequestData.class.getSimpleName();
       sw.println("public " + requestDataName + " getRequestData() {");
       sw.indent();
-      sw.println("return new " + requestDataName + "(\"" + operationName
-          + "\", " + getParametersAsString(method, typeOracle) + ", "
-          + "getPropertyRefs());");
+      sw.println("return new %s(\"%s\", %s, %s, getPropertyRefs());",
+          RequestData.class.getSimpleName(), operationName,
+          getParametersAsString(method, typeOracle),
+          getEntityParameters(method));
       sw.outdent();
       sw.println("}");
       sw.outdent();
@@ -775,12 +777,10 @@
    */
   private Class<?> getCollectionType(TypeOracle typeOracle,
       JClassType requestType) {
-    if (requestType.isAssignableTo(
-        typeOracle.findType(ProxyListRequest.class.getName()))) {
+    if (requestType.isAssignableTo(typeOracle.findType(ProxyListRequest.class.getName()))) {
       return List.class;
     }
-    if (requestType.isAssignableTo(typeOracle.findType(
-        ProxySetRequest.class.getName()))) {
+    if (requestType.isAssignableTo(typeOracle.findType(ProxySetRequest.class.getName()))) {
       return Set.class;
     }
     JClassType retType = requestType.isParameterized().getTypeArgs()[0];
@@ -797,6 +797,18 @@
     return null;
   }
 
+  private String getEntityParameters(JMethod method) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("new Object[] {");
+    for (JParameter param : method.getParameters()) {
+      if (mayContainEntityProxy(param.getType())) {
+        sb.append(param.getName()).append(",");
+      }
+    }
+    sb.append("}");
+    return sb.toString();
+  }
+
   /**
    * This method is very similar to {@link
    * com.google.gwt.core.ext.typeinfo.JMethod.getReadableDeclaration()}. The
@@ -838,11 +850,12 @@
       JClassType classType = parameter.getType().isClassOrInterface();
 
       JType paramType = parameter.getType();
-      if (paramType.getQualifiedSourceName().equals(EntityProxyId.class.getName())) {
+      if (paramType.getQualifiedSourceName().equals(
+          EntityProxyId.class.getName())) {
         sb.append("factory.getWireFormat(" + parameter.getName() + ")");
         continue;
       }
-      
+
       if (classType != null && classType.isAssignableTo(entityProxyType)) {
         sb.append("((" + classType.getQualifiedBinaryName() + "Impl" + ")");
       }
@@ -877,16 +890,14 @@
     return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Character.class.getName()));
   }
 
-  private boolean isCollection(TypeOracle typeOracle,
-      JType requestType) {
+  private boolean isCollection(TypeOracle typeOracle, JType requestType) {
     return requestType.isParameterized() != null
-            && requestType.isParameterized().isAssignableTo(
-        typeOracle.findType(Collection.class.getName()));
+        && requestType.isParameterized().isAssignableTo(
+            typeOracle.findType(Collection.class.getName()));
   }
 
   private boolean isDateRequest(TypeOracle typeOracle, JClassType requestType) {
-    return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(
-        Date.class.getName()));
+    return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Date.class.getName()));
   }
 
   private boolean isDoubleRequest(TypeOracle typeOracle, JClassType requestType) {
@@ -911,12 +922,10 @@
 
   private boolean isProxyCollectionRequest(TypeOracle typeOracle,
       JClassType requestType) {
-    return requestType.isAssignableTo(typeOracle.findType(
-        ProxyListRequest.class.getName()))
-        || requestType.isAssignableTo(typeOracle.findType(
-        ProxySetRequest.class.getName()));
+    return requestType.isAssignableTo(typeOracle.findType(ProxyListRequest.class.getName()))
+        || requestType.isAssignableTo(typeOracle.findType(ProxySetRequest.class.getName()));
   }
-  
+
   private boolean isProxyRequest(TypeOracle typeOracle, JClassType requestType) {
     return requestType.isAssignableTo(typeOracle.findType(ProxyRequest.class.getName()));
   }
@@ -974,9 +983,9 @@
       propertyName = Introspector.decapitalize(methodName.substring(3));
       propertyType = method.getReturnType();
       if (propertyType.isArray() != null) {
-        logger.log(TreeLogger.ERROR, "Method " + methodName
-        + " on " + method.getEnclosingType().getQualifiedSourceName()
-        + " may not return a Java array.");
+        logger.log(TreeLogger.ERROR, "Method " + methodName + " on "
+            + method.getEnclosingType().getQualifiedSourceName()
+            + " may not return a Java array.");
         throw new UnableToCompleteException();
       }
     } else if (methodName.startsWith("set")) {
@@ -985,9 +994,9 @@
       if (parameters.length > 0) {
         propertyType = parameters[parameters.length - 1].getType();
         if (propertyType.isArray() != null) {
-          logger.log(TreeLogger.ERROR, "Method " + methodName
-          + " on " + method.getEnclosingType().getQualifiedSourceName()
-          + " may accept a Java array as a parameter.");
+          logger.log(TreeLogger.ERROR, "Method " + methodName + " on "
+              + method.getEnclosingType().getQualifiedSourceName()
+              + " may accept a Java array as a parameter.");
           throw new UnableToCompleteException();
         }
       }
@@ -1002,6 +1011,16 @@
     return null;
   }
 
+  private boolean mayContainEntityProxy(JType paramType) {
+    JClassType paramClass = paramType.isClassOrInterface();
+    if (paramClass == null) {
+      return false;
+    }
+    return entityProxyType.isAssignableFrom(paramClass)
+        || listType.isAssignableFrom(paramClass)
+        || setType.isAssignableFrom(paramClass);
+  }
+
   /**
    * Prints a ListRequestImpl or ObjectRequestImpl class.
    */
@@ -1068,8 +1087,8 @@
       throw new RuntimeException(e);
     }
 
-    List<EntityProperty> entityProperties = computeEntityPropertiesFromProxyType(publicProxyType,
-        logger);
+    List<EntityProperty> entityProperties = computeEntityPropertiesFromProxyType(
+        publicProxyType, logger);
     for (EntityProperty entityProperty : entityProperties) {
       sw.println(String.format("set.add(%s);", entityProperty.getName()));
     }
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
index 1b20eac..6c95f8a 100644
--- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -157,8 +157,8 @@
     try {
       decodedBytes = Base64Utils.fromBase64(encoded);
     } catch (Exception e) {
-      throw new IllegalArgumentException(
-          "EntityKeyId was not Base64 encoded: " + encoded);
+      throw new IllegalArgumentException("EntityKeyId was not Base64 encoded: "
+          + encoded);
     }
     return new String(decodedBytes);
   }
@@ -210,7 +210,7 @@
 
   private Map<EntityKey, EntityData> afterDvsDataMap = new HashMap<EntityKey, EntityData>();
 
-  @SuppressWarnings({"unchecked", "rawtypes"})
+  @SuppressWarnings(value = {"unchecked", "rawtypes"})
   public Collection<Property<?>> allProperties(
       Class<? extends EntityProxy> clazz) throws IllegalArgumentException {
     return getPropertiesFromRecordProxyType(clazz).values();
@@ -403,9 +403,10 @@
     String encodedEntityId = isEntityReference(returnValue, proxyPropertyType);
 
     if (returnValue == null) {
-      return JSONObject.NULL;  
+      return JSONObject.NULL;
     } else if (encodedEntityId != null) {
-      String keyRef = encodeRelated(proxyPropertyType, propertyName, propertyContext, returnValue);
+      String keyRef = encodeRelated(proxyPropertyType, propertyName,
+          propertyContext, returnValue);
       return keyRef;
     } else if (property instanceof CollectionProperty) {
       Class<?> colType = ((CollectionProperty) property).getType();
@@ -461,9 +462,11 @@
     validateKeys(recordObject, propertiesInDomain.keySet());
 
     // get entityInstance
-    Object entityInstance = getEntityInstance(writeOperation, entityType,
-        entityKey.decodedId(propertiesInProxy.get(ENTITY_ID_PROPERTY).getType()), propertiesInProxy.get(
-            ENTITY_ID_PROPERTY).getType());
+    Object entityInstance = getEntityInstance(
+        writeOperation,
+        entityType,
+        entityKey.decodedId(propertiesInProxy.get(ENTITY_ID_PROPERTY).getType()),
+        propertiesInProxy.get(ENTITY_ID_PROPERTY).getType());
 
     cachedEntityLookup.put(entityKey, entityInstance);
 
@@ -607,18 +610,22 @@
     return jsonArray;
   }
 
-  public JSONObject getJsonObject(Object entityElement,
+  public Object getJsonObject(Object entityElement,
       Class<? extends EntityProxy> entityKeyClass,
       RequestProperty propertyContext) throws JSONException,
       NoSuchMethodException, IllegalAccessException, InvocationTargetException {
     JSONObject jsonObject = new JSONObject();
-    if (entityElement == null || !EntityProxy.class.isAssignableFrom(entityKeyClass)) {
-      return jsonObject;
+    if (entityElement == null
+        || !EntityProxy.class.isAssignableFrom(entityKeyClass)) {
+      // JSONObject.NULL isn't a JSONObject
+      return JSONObject.NULL;
     }
 
-    jsonObject.put(ENCODED_ID_PROPERTY, isEntityReference(entityElement, entityKeyClass));
-    jsonObject.put(ENCODED_VERSION_PROPERTY, encodePropertyValueFromDataStore(entityElement,
-          ENTITY_VERSION_PROPERTY, ENTITY_VERSION_PROPERTY.getName(), propertyContext));
+    jsonObject.put(ENCODED_ID_PROPERTY, isEntityReference(entityElement,
+        entityKeyClass));
+    jsonObject.put(ENCODED_VERSION_PROPERTY, encodePropertyValueFromDataStore(
+        entityElement, ENTITY_VERSION_PROPERTY,
+        ENTITY_VERSION_PROPERTY.getName(), propertyContext));
     for (Property<?> p : allProperties(entityKeyClass)) {
       if (requestedProperty(p, propertyContext)) {
         String propertyName = p.getName();
@@ -866,7 +873,8 @@
 
     JSONObject sideEffects = getSideEffects();
 
-    if ((result instanceof List<?>) != operation.isReturnTypeList()) {
+    if (result != null
+        && (result instanceof List<?>) != operation.isReturnTypeList()) {
       throw new IllegalArgumentException(
           String.format("Type mismatch, expected %s%s, but %s returns %s",
               operation.isReturnTypeList() ? "list of " : "",
@@ -887,11 +895,13 @@
         // HACK.
         if (involvedKeys.size() == 1) {
           returnType = involvedKeys.iterator().next().proxyType;
+        } else {
+          System.out.println("null find");
         }
       } else {
         returnType = (Class<? extends EntityProxy>) operation.getReturnType();
       }
-      JSONObject jsonObject = getJsonObject(result, returnType, propertyRefs);
+      Object jsonObject = getJsonObject(result, returnType, propertyRefs);
       envelop.put(RESULT_TOKEN, jsonObject);
     }
     envelop.put(SIDE_EFFECTS_TOKEN, sideEffects);
@@ -1012,10 +1022,12 @@
     if (!relatedObjects.containsKey(keyRef)) {
       // put temporary value to prevent infinite recursion
       relatedObjects.put(keyRef, null);
-      JSONObject jsonObject = getJsonObject(returnValue, propertyType,
+      Object jsonObject = getJsonObject(returnValue, propertyType,
           propertyContext);
-      // put real value
-      relatedObjects.put(keyRef, jsonObject);
+      if (jsonObject != JSONObject.NULL) { 
+        // put real value
+        relatedObjects.put(keyRef, (JSONObject) jsonObject);
+      }
     }
   }
 
@@ -1064,24 +1076,16 @@
           // TODO: assert that the id is null for entityData.entityInstance
         }
         afterDvsDataMap.put(entityKey, entityData);
+      } else if (entityKey.isFuture) {
+        // The client-side DVS failed to include a CREATE operation.
+        throw new RuntimeException("Future object with no dvsData");
       } else {
-        if (entityKey.isFuture) {
-          /*
-           * dummy create, i.e., an entity for which RequestFactory#create was
-           * called, but for which no values were set, so it is not listed in
-           * the dvs TODO(rjrjr) silly to work around this on the server. Fix
-           * the client.
-           */
-          JSONObject dummyJson = new JSONObject();
-          dummyJson.put(ENCODED_ID_PROPERTY, entityKey.encodedId);
-          afterDvsDataMap.put(entityKey,
-              getEntityDataForRecordWithSettersApplied(entityKey, dummyJson,
-                  WriteOperation.CREATE));
-        } else {
-          // Involved, but not in the deltaValueStore -- param ref to an
-          // unedited existing object
-          SerializedEntity serializedEntity = beforeDataMap.get(entityKey);
-          assert serializedEntity.entityInstance != null;
+        /*
+         * Involved, but not in the deltaValueStore -- param ref to an unedited,
+         * existing object.
+         */
+        SerializedEntity serializedEntity = beforeDataMap.get(entityKey);
+        if (serializedEntity.entityInstance != null) {
           afterDvsDataMap.put(entityKey, new EntityData(
               serializedEntity.entityInstance, null));
         }
@@ -1206,7 +1210,8 @@
     Object entityInstance = entityData.entityInstance;
     assert entityInstance != null;
     JSONObject returnObject = new JSONObject();
-    returnObject.put(ENCODED_FUTUREID_PROPERTY, originalEntityKey.encodedId + "");
+    returnObject.put(ENCODED_FUTUREID_PROPERTY, originalEntityKey.encodedId
+        + "");
     // violations have already been taken care of.
     Object newId = getRawPropertyValueFromDatastore(entityInstance,
         ENTITY_ID_PROPERTY, propertyRefs);
@@ -1217,10 +1222,12 @@
     }
 
     newId = encodeId(newId);
-    returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(originalEntityKey.proxyType, newId));
-    returnObject.put(ENCODED_VERSION_PROPERTY, encodePropertyValueFromDataStore(
-        entityInstance, ENTITY_VERSION_PROPERTY,
-        ENTITY_VERSION_PROPERTY.getName(), propertyRefs));
+    returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(
+        originalEntityKey.proxyType, newId));
+    returnObject.put(ENCODED_VERSION_PROPERTY,
+        encodePropertyValueFromDataStore(entityInstance,
+            ENTITY_VERSION_PROPERTY, ENTITY_VERSION_PROPERTY.getName(),
+            propertyRefs));
     return returnObject;
   }
 
@@ -1347,14 +1354,14 @@
           entityData);
       if (writeOperation == WriteOperation.DELETE) {
         JSONObject deleteRecord = new JSONObject();
-        deleteRecord.put(ENCODED_ID_PROPERTY, getSchemaAndId(entityKey.proxyType,
-            entityKey.encodedId));
+        deleteRecord.put(ENCODED_ID_PROPERTY, getSchemaAndId(
+            entityKey.proxyType, entityKey.encodedId));
         deleteArray.put(deleteRecord);
       }
       if (writeOperation == WriteOperation.UPDATE) {
         JSONObject updateRecord = new JSONObject();
-        updateRecord.put(ENCODED_ID_PROPERTY, getSchemaAndId(entityKey.proxyType,
-            entityKey.encodedId));
+        updateRecord.put(ENCODED_ID_PROPERTY, getSchemaAndId(
+            entityKey.proxyType, entityKey.encodedId));
         updateArray.put(updateRecord);
       }
     }
@@ -1384,10 +1391,11 @@
         returnObject.put(VIOLATIONS_TOKEN, entityData.violations);
         if (entityKey.isFuture) {
           returnObject.put(ENCODED_FUTUREID_PROPERTY, entityKey.encodedId);
-          returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(entityKey.proxyType, null));
+          returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(
+              entityKey.proxyType, null));
         } else {
-          returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(entityKey.proxyType,
-              entityKey.encodedId));
+          returnObject.put(ENCODED_ID_PROPERTY, getSchemaAndId(
+              entityKey.proxyType, entityKey.encodedId));
         }
         violations.put(returnObject);
       }
@@ -1453,7 +1461,7 @@
       Object propertyValue;
       String encodedEntityId = isEntityReference(returnValue, p.getType());
       if (returnValue == null) {
-          propertyValue = JSONObject.NULL;
+        propertyValue = JSONObject.NULL;
       } else if (encodedEntityId != null) {
         propertyValue = encodedEntityId
             + "@NO@"
diff --git a/user/src/com/google/gwt/requestfactory/shared/Receiver.java b/user/src/com/google/gwt/requestfactory/shared/Receiver.java
index 7d89ca4..8ba90ae 100644
--- a/user/src/com/google/gwt/requestfactory/shared/Receiver.java
+++ b/user/src/com/google/gwt/requestfactory/shared/Receiver.java
@@ -33,13 +33,7 @@
    * RuntimeException with the provided error message.
    */
   public void onFailure(ServerFailure error) {
-    String exceptionType = error.getExceptionType();
-    String message = error.getMessage();
-    throw new RuntimeException(exceptionType
-        + ((exceptionType.length() != 0 && message.length() != 0) ? ": " : "")
-        + error.getMessage()
-        + ((exceptionType.length() != 0 || message.length() != 0) ? ": " : "")
-        + error.getStackTraceString());
+    throw new RuntimeException(error.getMessage());
   }
 
   /**
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
index 46f3d43..f369ce8 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
@@ -73,14 +73,25 @@
 
   private final String operation;
   private final Object[] parameters;
-
   private final Set<String> propertyRefs;
+  // Could be EntityProxy or Collection instances
+  private final Object[] proxies;
 
-  public RequestData(String operation, Object[] parameters,
+  public RequestData(String operation, Object[] parameters, Object[] proxies,
       Set<String> propertyRefs) {
     this.operation = operation;
     this.parameters = parameters;
     this.propertyRefs = propertyRefs;
+    this.proxies = proxies;
+  }
+
+  /**
+   * Returns any EntityProxies being passed as method arguments. Prevents the
+   * "dummy object" case.
+   * @return EntityProxies or Collections
+   */
+  public Object[] getProxyParameters() {
+    return proxies;
   }
 
   /**
@@ -119,11 +130,11 @@
       return "null";
     }
 
-    if (value instanceof Iterable) {
+    if (value instanceof Iterable<?>) {
       StringBuffer toReturn = new StringBuffer();
       toReturn.append('[');
       boolean first = true;
-      for (Object val : ((Iterable) value)) {
+      for (Object val : ((Iterable<?>) value)) {
         if (!first) {
           toReturn.append(',');
         } else {
@@ -147,8 +158,8 @@
       return asJsonString(((Date) value).getTime());
     }
 
-    if (value instanceof Enum) {
-      return asJsonString(((Enum) value).ordinal());
+    if (value instanceof Enum<?>) {
+      return asJsonString(((Enum<?>) value).ordinal());
     }
     
     return value.toString();
diff --git a/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java b/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java
index 0a59821..adb0efe 100644
--- a/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java
@@ -15,10 +15,15 @@
  */
 package com.google.gwt.requestfactory.client;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.SimpleEventBus;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
+import com.google.gwt.requestfactory.shared.ProxyRequest;
 import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.Request;
 import com.google.gwt.requestfactory.shared.SimpleBarProxy;
 import com.google.gwt.requestfactory.shared.SimpleFooProxy;
+import com.google.gwt.requestfactory.shared.SimpleRequestFactory;
 
 /**
  * Tests for {@link com.google.gwt.requestfactory.shared.RequestFactory}.
@@ -28,14 +33,46 @@
    * DO NOT USE finishTest(). Instead, call finishTestAndReset();
    */
 
+  private static final int TEST_DELAY = 5000;
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.requestfactory.RequestFactorySuite";
   }
 
+  public void testFetchDeletedEntity() {
+    delayTestFinish(TEST_DELAY);
+    SimpleBarProxy willDelete = req.create(SimpleBarProxy.class);
+    req.simpleBarRequest().persistAndReturnSelf(willDelete).fire(
+        new Receiver<SimpleBarProxy>() {
+          @Override
+          public void onSuccess(SimpleBarProxy response) {
+            final EntityProxyId<SimpleBarProxy> id = response.stableId();
+
+            // Make the entity behave as though it's been deleted
+            Request<Void> persist = req.simpleBarRequest().persist(response);
+            persist.edit(response).setFindFails(true);
+            persist.fire(new Receiver<Void>() {
+
+              @Override
+              public void onSuccess(Void response) {
+                // Now try fetching the deleted instance
+                req.find(id).fire(new Receiver<SimpleBarProxy>() {
+                  @Override
+                  public void onSuccess(SimpleBarProxy response) {
+                    assertNull(response);
+                    finishTestAndReset();
+                  }
+                });
+              }
+            });
+          }
+        });
+  }
+
   public void testFetchEntityWithLongId() {
     final boolean relationsAbsent = false;
-    delayTestFinish(5000);
+    delayTestFinish(TEST_DELAY);
     req.simpleFooRequest().findSimpleFooById(999L).fire(
         new Receiver<SimpleFooProxy>() {
           @Override
@@ -58,7 +95,7 @@
 
   public void testFetchEntityWithRelation() {
     final boolean relationsPresent = true;
-    delayTestFinish(5000);
+    delayTestFinish(TEST_DELAY);
     req.simpleFooRequest().findSimpleFooById(999L).with("barField").fire(
         new Receiver<SimpleFooProxy>() {
           @Override
@@ -79,9 +116,9 @@
           }
         });
   }
-  
+
   public void testFetchEntityWithStringId() {
-    delayTestFinish(5000);
+    delayTestFinish(TEST_DELAY);
     req.simpleBarRequest().findSimpleBarById("999L").fire(
         new Receiver<SimpleBarProxy>() {
           @Override
@@ -100,6 +137,36 @@
         });
   }
 
+  /**
+   * Demonstrates behavior when fetching an unpersisted id. The setup is
+   * analagous to saving a future id into a cookie and then trying to fetch it
+   * later.
+   */
+  public void testFetchUnpersistedFutureId() {
+    String historyToken;
+
+    // Here's the factory from the "previous invocation" of the client
+    {
+      SimpleRequestFactory oldFactory = GWT.create(SimpleRequestFactory.class);
+      oldFactory.initialize(new SimpleEventBus());
+      EntityProxyId<SimpleBarProxy> id = oldFactory.create(SimpleBarProxy.class).stableId();
+      historyToken = oldFactory.getHistoryToken(id);
+    }
+
+    EntityProxyId<SimpleBarProxy> id = req.getProxyId(historyToken);
+    assertNotNull(id);
+    ProxyRequest<SimpleBarProxy> find = req.find(id);
+    try {
+      find.fire(new Receiver<SimpleBarProxy>() {
+        @Override
+        public void onSuccess(SimpleBarProxy response) {
+          fail("Request should never have been made");
+        }
+      });
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
   private void checkReturnedProxy(SimpleFooProxy response,
       boolean checkForRelations) {
     assertEquals(42, (int) response.getIntId());
@@ -114,4 +181,3 @@
     }
   }
 }
-
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
index 86361f4..d31efff 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryStringTest.java
@@ -126,8 +126,9 @@
         assertEquals(futureId, foo.getId());
         assertTrue(((ProxyImpl) foo).unpersisted());
 
-        assertEquals(1, handler.acquireEventCount);
+        assertEquals(0, handler.acquireEventCount);
         assertEquals(1, handler.createEventCount);
+        assertEquals(1, handler.updateEventCount);
         assertEquals(2, handler.totalEventCount);
 
         checkStableIdEquals(foo, returned);
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index d31f951..8319d2d 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -27,8 +27,8 @@
 import com.google.gwt.requestfactory.shared.SimpleFooProxy;
 import com.google.gwt.requestfactory.shared.Violation;
 
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -47,8 +47,8 @@
     private SimpleFooProxy mutableFoo;
     private Request<SimpleFooProxy> persistRequest;
     private String expectedException;
-    
-    public FooReciever(SimpleFooProxy mutableFoo, 
+
+    public FooReciever(SimpleFooProxy mutableFoo,
         Request<SimpleFooProxy> persistRequest, String exception) {
       this.mutableFoo = mutableFoo;
       this.persistRequest = persistRequest;
@@ -60,8 +60,7 @@
       assertEquals(expectedException, error.getExceptionType());
       if (expectedException.length() > 0) {
         assertFalse(error.getStackTraceString().length() == 0);
-        assertEquals("THIS EXCEPTION IS EXPECTED BY A TEST",
-            error.getMessage());
+        assertEquals("THIS EXCEPTION IS EXPECTED BY A TEST", error.getMessage());
       } else {
         assertEquals("", error.getStackTraceString());
         assertEquals("Server Error: THIS EXCEPTION IS EXPECTED BY A TEST",
@@ -91,6 +90,14 @@
     }
   }
 
+  class NullReceiver extends Receiver<Object> {
+    @Override
+    public void onSuccess(Object response) {
+      assertNull(response);
+      finishTestAndReset();
+    }
+  }
+
   private class FailFixAndRefire<T> extends Receiver<T> {
 
     private final SimpleFooProxy proxy;
@@ -155,14 +162,14 @@
     }
   }
 
-  public <T extends EntityProxy> void assertContains(Collection<T> col,
-      T value) {
+  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,13 +192,12 @@
     assertEquals(SimpleFooProxy.class, foo.stableId().getProxyClass());
   }
 
-  public void  testDummyCreate() {
+  public void testDummyCreate() {
     delayTestFinish(5000);
 
-    final SimpleFooEventHandler<SimpleFooProxy> handler = 
-      new SimpleFooEventHandler<SimpleFooProxy>();
-    EntityProxyChange.registerForProxyType(
-        req.getEventBus(), SimpleFooProxy.class, handler);
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
 
     final SimpleFooProxy foo = req.create(SimpleFooProxy.class);
     Object futureId = foo.getId();
@@ -207,8 +213,9 @@
         assertEquals(futureId, foo.getId());
         assertTrue(((ProxyImpl) foo).unpersisted());
 
-        assertEquals(1, handler.acquireEventCount);
+        assertEquals(0, handler.acquireEventCount);
         assertEquals(1, handler.createEventCount);
+        assertEquals(1, handler.updateEventCount);
         assertEquals(2, handler.totalEventCount);
 
         checkStableIdEquals(foo, returned);
@@ -240,6 +247,30 @@
     });
   }
 
+  public void testDummyCreateList() {
+    delayTestFinish(500000);
+
+    final SimpleBarProxy bar = req.create(SimpleBarProxy.class);
+    Object futureId = bar.getId();
+    assertEquals(futureId, bar.getId());
+    assertTrue(((ProxyImpl) bar).unpersisted());
+    Request<SimpleBarProxy> fooReq = req.simpleBarRequest().returnFirst(
+        Collections.singletonList(bar));
+    fooReq.fire(new Receiver<SimpleBarProxy>() {
+
+      @Override
+      public void onSuccess(final SimpleBarProxy returned) {
+        Object futureId = bar.getId();
+        assertEquals(futureId, bar.getId());
+        assertTrue(((ProxyImpl) bar).unpersisted());
+        assertFalse(((ProxyImpl) returned).unpersisted());
+
+        checkStableIdEquals(bar, returned);
+        finishTestAndReset();
+      }
+    });
+  }
+
   public void testFetchEntity() {
     delayTestFinish(5000);
     req.simpleFooRequest().findSimpleFooById(999L).fire(
@@ -276,19 +307,18 @@
 
   public void testFetchList() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findAll().fire(
-        new Receiver<List<SimpleFooProxy>>() {
-          @Override
-          public void onSuccess(List<SimpleFooProxy> responseList) {
-            SimpleFooProxy response = responseList.get(0);
-            assertEquals(42, (int) response.getIntId());
-            assertEquals("GWT", response.getUserName());
-            assertEquals(8L, (long) response.getLongField());
-            assertEquals(com.google.gwt.requestfactory.shared.SimpleEnum.FOO,
-                response.getEnumField());
-            finishTestAndReset();
-          }
-        });
+    req.simpleFooRequest().findAll().fire(new Receiver<List<SimpleFooProxy>>() {
+      @Override
+      public void onSuccess(List<SimpleFooProxy> responseList) {
+        SimpleFooProxy response = responseList.get(0);
+        assertEquals(42, (int) response.getIntId());
+        assertEquals("GWT", response.getUserName());
+        assertEquals(8L, (long) response.getLongField());
+        assertEquals(com.google.gwt.requestfactory.shared.SimpleEnum.FOO,
+            response.getEnumField());
+        finishTestAndReset();
+      }
+    });
   }
 
   public void testFetchSet() {
@@ -369,17 +399,43 @@
         // Check that the persisted object can be found with future token
         assertEquals(futureId, req.getProxyId(futureToken));
         assertEquals(futureId, req.getProxyId(persistedToken));
-        assertEquals(futureId.getProxyClass(), req.getProxyClass(persistedToken));
+        assertEquals(futureId.getProxyClass(),
+            req.getProxyClass(persistedToken));
 
         assertEquals(persistedId, req.getProxyId(futureToken));
         assertEquals(persistedId, req.getProxyId(persistedToken));
-        assertEquals(persistedId.getProxyClass(), req.getProxyClass(futureToken));
+        assertEquals(persistedId.getProxyClass(),
+            req.getProxyClass(futureToken));
 
         finishTestAndReset();
       }
     });
   }
 
+  /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullListResult() {
+    delayTestFinish(5000);
+    req.simpleFooRequest().returnNullList().fire(new NullReceiver());
+  }
+
+  /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullEntityProxyResult() {
+    delayTestFinish(5000);
+    req.simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
+  }
+
+  /**
+   * Ensures that a service method can respond with a null value.
+   */
+  public void testNullStringResult() {
+    delayTestFinish(5000);
+    req.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
@@ -388,10 +444,9 @@
   public void testMethodWithSideEffects() {
     delayTestFinish(5000);
 
-    final SimpleFooEventHandler<SimpleFooProxy> handler = 
-      new SimpleFooEventHandler<SimpleFooProxy>();
-    EntityProxyChange.registerForProxyType(
-        req.getEventBus(), SimpleFooProxy.class, handler);
+    final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
+    EntityProxyChange.registerForProxyType(req.getEventBus(),
+        SimpleFooProxy.class, handler);
 
     req.simpleFooRequest().findSimpleFooById(999L).fire(
         new Receiver<SimpleFooProxy>() {
@@ -471,7 +526,7 @@
           }
         });
   }
-  
+
   /*
    * Find Entity Create Entity2 Relate Entity2 to Entity Persist Entity
    */
@@ -495,8 +550,7 @@
               public void onSuccess(SimpleFooProxy response) {
 
                 // Found the foo, edit it
-                Request<Void> fooReq = req.simpleFooRequest().persist(
-                    response);
+                Request<Void> fooReq = req.simpleFooRequest().persist(response);
                 response = fooReq.edit(response);
                 response.setBarField(persistedBar);
                 fooReq.fire(new Receiver<Void>() {
@@ -562,6 +616,29 @@
         });
   }
 
+  /**
+   * Ensure that a relationship can be set up between two newly-created objects.
+   */
+  public void testPersistFutureToFuture() {
+    delayTestFinish(500000);
+    SimpleFooProxy newFoo = req.create(SimpleFooProxy.class);
+    final SimpleBarProxy newBar = req.create(SimpleBarProxy.class);
+
+    Request<SimpleFooProxy> fooReq = req.simpleFooRequest().persistAndReturnSelf(
+        newFoo).with("barField");
+    newFoo = fooReq.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
@@ -624,30 +701,28 @@
         new Receiver<SimpleBarProxy>() {
           @Override
           public void onSuccess(final SimpleBarProxy barProxy) {
-            req.simpleFooRequest().findSimpleFooById(999L).with("oneToManyField").fire(
-                new Receiver<SimpleFooProxy>() {
-                  @Override
-                  public void onSuccess(SimpleFooProxy fooProxy) {
-                    Request<SimpleFooProxy> updReq =
-                        req.simpleFooRequest().persistAndReturnSelf(
-                        fooProxy).with("oneToManyField");
-                    fooProxy = updReq.edit(fooProxy);
+            req.simpleFooRequest().findSimpleFooById(999L).with(
+                "oneToManyField").fire(new Receiver<SimpleFooProxy>() {
+              @Override
+              public void onSuccess(SimpleFooProxy fooProxy) {
+                Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                    fooProxy).with("oneToManyField");
+                fooProxy = updReq.edit(fooProxy);
 
-                    List<SimpleBarProxy> barProxyList =
-                        fooProxy.getOneToManyField();
-                    final int listCount = barProxyList.size();
-                    barProxyList.add(barProxy);
-                    updReq.fire(new Receiver<SimpleFooProxy>() {
-                      @Override
-                      public void onSuccess(SimpleFooProxy response) {
-                        assertEquals(response.getOneToManyField().size(),
-                            listCount + 1);
-                        assertContains(response.getOneToManyField(), barProxy);
-                        finishTestAndReset();
-                      }
-                    });
+                List<SimpleBarProxy> barProxyList = fooProxy.getOneToManyField();
+                final int listCount = barProxyList.size();
+                barProxyList.add(barProxy);
+                updReq.fire(new Receiver<SimpleFooProxy>() {
+                  @Override
+                  public void onSuccess(SimpleFooProxy response) {
+                    assertEquals(response.getOneToManyField().size(),
+                        listCount + 1);
+                    assertContains(response.getOneToManyField(), barProxy);
+                    finishTestAndReset();
                   }
                 });
+              }
+            });
           }
         });
   }
@@ -678,8 +753,8 @@
     delayTestFinish(5000);
 
     SimpleFooProxy rayFoo = req.create(SimpleFooProxy.class);
-    final Request<SimpleFooProxy> persistRay = req.simpleFooRequest()
-        .persistAndReturnSelf(rayFoo);
+    final Request<SimpleFooProxy> persistRay = req.simpleFooRequest().persistAndReturnSelf(
+        rayFoo);
     rayFoo = persistRay.edit(rayFoo);
     rayFoo.setUserName("Ray");
 
@@ -687,8 +762,8 @@
       @Override
       public void onSuccess(final SimpleFooProxy persistedRay) {
         SimpleBarProxy amitBar = req.create(SimpleBarProxy.class);
-        final Request<SimpleBarProxy> persistAmit = req.simpleBarRequest()
-            .persistAndReturnSelf(amitBar);
+        final Request<SimpleBarProxy> persistAmit = req.simpleBarRequest().persistAndReturnSelf(
+            amitBar);
         amitBar = persistAmit.edit(amitBar);
         amitBar.setUserName("Amit");
 
@@ -696,9 +771,8 @@
           @Override
           public void onSuccess(SimpleBarProxy persistedAmit) {
 
-            final Request<SimpleFooProxy> persistRelationship = req
-                .simpleFooRequest().persistAndReturnSelf(persistedRay)
-                .with("barField");
+            final Request<SimpleFooProxy> persistRelationship = req.simpleFooRequest().persistAndReturnSelf(
+                persistedRay).with("barField");
             SimpleFooProxy newRec = persistRelationship.edit(persistedRay);
             newRec.setBarField(persistedAmit);
 
@@ -716,20 +790,19 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
 
   public void testPersistSelfOneToManyExistingEntityExistingRelation() {
     delayTestFinish(5000);
 
-    req.simpleFooRequest().findSimpleFooById(999L).with("selfOneToManyField")
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).with("selfOneToManyField").fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy).with(
-                    "selfOneToManyField");
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy).with("selfOneToManyField");
             fooProxy = updReq.edit(fooProxy);
             List<SimpleFooProxy> fooProxyList = fooProxy.getSelfOneToManyField();
             final int listCount = fooProxyList.size();
@@ -749,12 +822,12 @@
 
   public void testPersistValueList() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
             fooProxy.getNumberListField().add(100);
             updReq.fire(new Receiver<SimpleFooProxy>() {
@@ -769,17 +842,17 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueListNull() {
     delayTestFinish(500000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
 
             fooProxy.setNumberListField(null);
@@ -787,7 +860,7 @@
               @Override
               public void onSuccess(SimpleFooProxy response) {
                 List<Integer> list = response.getNumberListField();
-                assertNull(list);            
+                assertNull(list);
                 finishTestAndReset();
               }
             });
@@ -796,17 +869,17 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueListRemove() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
             final int oldValue = fooProxy.getNumberListField().remove(0);
             updReq.fire(new Receiver<SimpleFooProxy>() {
@@ -821,17 +894,17 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueListReplace() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
             final ArrayList<Integer> al = new ArrayList<Integer>();
             al.add(5);
@@ -851,19 +924,19 @@
           }
         });
   }
-  
+
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueListReverse() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
             final ArrayList<Integer> al = new ArrayList<Integer>();
             List<Integer> listField = fooProxy.getNumberListField();
@@ -882,17 +955,17 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueListSetIndex() {
     delayTestFinish(5000);
-    req.simpleFooRequest().findSimpleFooById(999L)
-        .fire(new Receiver<SimpleFooProxy>() {
+    req.simpleFooRequest().findSimpleFooById(999L).fire(
+        new Receiver<SimpleFooProxy>() {
           @Override
           public void onSuccess(SimpleFooProxy fooProxy) {
-            Request<SimpleFooProxy> updReq =
-                req.simpleFooRequest().persistAndReturnSelf(fooProxy);
+            Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                fooProxy);
             fooProxy = updReq.edit(fooProxy);
             fooProxy.getNumberListField().set(0, 10);
             updReq.fire(new Receiver<SimpleFooProxy>() {
@@ -907,9 +980,9 @@
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueSetAddNew() {
     delayTestFinish(5000);
     SimpleBarProxy newBar = req.create(SimpleBarProxy.class);
@@ -918,39 +991,36 @@
         new Receiver<SimpleBarProxy>() {
           @Override
           public void onSuccess(final SimpleBarProxy barProxy) {
-            req.simpleFooRequest().findSimpleFooById(999L).with("oneToManySetField").fire(
-                new Receiver<SimpleFooProxy>() {
-                  @Override
-                  public void onSuccess(SimpleFooProxy fooProxy) {
-                    Request<SimpleFooProxy> updReq =
-                        req.simpleFooRequest().persistAndReturnSelf(
-                        fooProxy).with("oneToManySetField");
-                    fooProxy = updReq.edit(fooProxy);
+            req.simpleFooRequest().findSimpleFooById(999L).with(
+                "oneToManySetField").fire(new Receiver<SimpleFooProxy>() {
+              @Override
+              public void onSuccess(SimpleFooProxy fooProxy) {
+                Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                    fooProxy).with("oneToManySetField");
+                fooProxy = updReq.edit(fooProxy);
 
-                    Set<SimpleBarProxy> setField =
-                        fooProxy.getOneToManySetField();
-                    final int listCount = setField.size();
-                    setField.add(barProxy);
-                    updReq.fire(new Receiver<SimpleFooProxy>() {
-                      @Override
-                      public void onSuccess(SimpleFooProxy response) {
-                        assertEquals(listCount + 1,
-                            response.getOneToManySetField().size());
-                        assertContains(response.getOneToManySetField(),
-                            barProxy);
-                        finishTestAndReset();
-                      }
-                    });
+                Set<SimpleBarProxy> setField = fooProxy.getOneToManySetField();
+                final int listCount = setField.size();
+                setField.add(barProxy);
+                updReq.fire(new Receiver<SimpleFooProxy>() {
+                  @Override
+                  public void onSuccess(SimpleFooProxy response) {
+                    assertEquals(listCount + 1,
+                        response.getOneToManySetField().size());
+                    assertContains(response.getOneToManySetField(), barProxy);
+                    finishTestAndReset();
                   }
                 });
+              }
+            });
           }
         });
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueSetAlreadyExists() {
     delayTestFinish(5000);
 
@@ -958,40 +1028,37 @@
         new Receiver<SimpleBarProxy>() {
           @Override
           public void onSuccess(final SimpleBarProxy barProxy) {
-            req.simpleFooRequest().findSimpleFooById(999L).with("oneToManySetField").fire(
-                new Receiver<SimpleFooProxy>() {
-                  @Override
-                  public void onSuccess(SimpleFooProxy fooProxy) {
-                    Request<SimpleFooProxy> updReq =
-                        req.simpleFooRequest().persistAndReturnSelf(
-                        fooProxy).with("oneToManySetField");
-                    fooProxy = updReq.edit(fooProxy);
+            req.simpleFooRequest().findSimpleFooById(999L).with(
+                "oneToManySetField").fire(new Receiver<SimpleFooProxy>() {
+              @Override
+              public void onSuccess(SimpleFooProxy fooProxy) {
+                Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                    fooProxy).with("oneToManySetField");
+                fooProxy = updReq.edit(fooProxy);
 
-                    Set<SimpleBarProxy> setField =
-                        fooProxy.getOneToManySetField();
-                    final int listCount = setField.size();
-                    assertContains(setField, barProxy);
-                    setField.add(barProxy);
-                    updReq.fire(new Receiver<SimpleFooProxy>() {
-                      @Override
-                      public void onSuccess(SimpleFooProxy response) {
-                        assertEquals(response.getOneToManySetField().size(),
-                            listCount);
-                        assertContains(response.getOneToManySetField(),
-                            barProxy);
-                        finishTestAndReset();
-                      }
-                    });
+                Set<SimpleBarProxy> setField = fooProxy.getOneToManySetField();
+                final int listCount = setField.size();
+                assertContains(setField, barProxy);
+                setField.add(barProxy);
+                updReq.fire(new Receiver<SimpleFooProxy>() {
+                  @Override
+                  public void onSuccess(SimpleFooProxy response) {
+                    assertEquals(response.getOneToManySetField().size(),
+                        listCount);
+                    assertContains(response.getOneToManySetField(), barProxy);
+                    finishTestAndReset();
                   }
                 });
+              }
+            });
           }
         });
   }
 
   /*
-  * TODO: all these tests should check the final values. It will be easy when
-  * we have better persistence than the singleton pattern.
-  */
+   * TODO: all these tests should check the final values. It will be easy when
+   * we have better persistence than the singleton pattern.
+   */
   public void testPersistValueSetRemove() {
     delayTestFinish(5000);
 
@@ -999,33 +1066,30 @@
         new Receiver<SimpleBarProxy>() {
           @Override
           public void onSuccess(final SimpleBarProxy barProxy) {
-            req.simpleFooRequest().findSimpleFooById(999L).with("oneToManySetField").fire(
-                new Receiver<SimpleFooProxy>() {
-                  @Override
-                  public void onSuccess(SimpleFooProxy fooProxy) {
-                    Request<SimpleFooProxy> updReq =
-                        req.simpleFooRequest().persistAndReturnSelf(
-                        fooProxy).with("oneToManySetField");
-                    fooProxy = updReq.edit(fooProxy);
+            req.simpleFooRequest().findSimpleFooById(999L).with(
+                "oneToManySetField").fire(new Receiver<SimpleFooProxy>() {
+              @Override
+              public void onSuccess(SimpleFooProxy fooProxy) {
+                Request<SimpleFooProxy> updReq = req.simpleFooRequest().persistAndReturnSelf(
+                    fooProxy).with("oneToManySetField");
+                fooProxy = updReq.edit(fooProxy);
 
-                    Set<SimpleBarProxy> setField =
-                        fooProxy.getOneToManySetField();
-                    final int listCount = setField.size();
-                    assertContains(setField, barProxy);
-                    setField.remove(barProxy);
-                    assertNotContains(setField, barProxy);
-                    updReq.fire(new Receiver<SimpleFooProxy>() {
-                      @Override
-                      public void onSuccess(SimpleFooProxy response) {
-                        assertEquals(listCount - 1,
-                            response.getOneToManySetField().size());
-                        assertNotContains(response.getOneToManySetField(),
-                            barProxy);
-                        finishTestAndReset();
-                      }
-                    });
+                Set<SimpleBarProxy> setField = fooProxy.getOneToManySetField();
+                final int listCount = setField.size();
+                assertContains(setField, barProxy);
+                setField.remove(barProxy);
+                assertNotContains(setField, barProxy);
+                updReq.fire(new Receiver<SimpleFooProxy>() {
+                  @Override
+                  public void onSuccess(SimpleFooProxy response) {
+                    assertEquals(listCount - 1,
+                        response.getOneToManySetField().size());
+                    assertNotContains(response.getOneToManySetField(), barProxy);
+                    finishTestAndReset();
                   }
                 });
+              }
+            });
           }
         });
   }
@@ -1047,19 +1111,19 @@
 
   public void testPrimitiveListAsParameter() {
     delayTestFinish(5000);
-    final Request<SimpleFooProxy> fooReq =
-        req.simpleFooRequest().findSimpleFooById(999L);
+    final Request<SimpleFooProxy> fooReq = req.simpleFooRequest().findSimpleFooById(
+        999L);
     fooReq.fire(new Receiver<SimpleFooProxy>() {
       public void onSuccess(SimpleFooProxy response) {
-         final Request<Integer> sumReq = req.simpleFooRequest().sum(
-             response, Arrays.asList(1,2,3));
-         sumReq.fire(new Receiver<Integer>() {
-           @Override
-           public void onSuccess(Integer response) {
-             assertEquals(6, response.intValue());
-             finishTestAndReset();
-           }
-         });
+        final Request<Integer> sumReq = req.simpleFooRequest().sum(response,
+            Arrays.asList(1, 2, 3));
+        sumReq.fire(new Receiver<Integer>() {
+          @Override
+          public void onSuccess(Integer response) {
+            assertEquals(6, response.intValue());
+            finishTestAndReset();
+          }
+        });
       }
     });
   }
@@ -1084,7 +1148,7 @@
 
     final Date date = new Date(90, 0, 1);
     Request<Date> procReq = req.simpleFooRequest().processDateList(
-             Arrays.asList(date));
+        Arrays.asList(date));
     procReq.fire(new Receiver<Date>() {
       @Override
       public void onSuccess(Date response) {
@@ -1106,7 +1170,7 @@
         assertEquals(SimpleEnum.BAR, response);
         finishTestAndReset();
       }
-    });       
+    });
   }
 
   public void testPrimitiveSet() {
@@ -1127,7 +1191,8 @@
   public void testPrimitiveString() {
     delayTestFinish(5000);
     final String testString = "test\"string\'with\nstring\u2060characters\t";
-    final Request<String> fooReq = req.simpleFooRequest().processString(testString);
+    final Request<String> fooReq = req.simpleFooRequest().processString(
+        testString);
     fooReq.fire(new Receiver<String>() {
       @Override
       public void onSuccess(String response) {
@@ -1139,7 +1204,8 @@
 
   public void testProxyList() {
     delayTestFinish(5000);
-    final Request<SimpleFooProxy> fooReq = req.simpleFooRequest().findSimpleFooById(999L).with("oneToManyField");
+    final Request<SimpleFooProxy> fooReq = req.simpleFooRequest().findSimpleFooById(
+        999L).with("oneToManyField");
     fooReq.fire(new Receiver<SimpleFooProxy>() {
       @Override
       public void onSuccess(SimpleFooProxy response) {
@@ -1151,24 +1217,23 @@
 
   public void testProxyListAsParameter() {
     delayTestFinish(5000);
-    final Request<SimpleFooProxy> fooReq =
-        req.simpleFooRequest().findSimpleFooById(999L).with("selfOneToManyField");
+    final Request<SimpleFooProxy> fooReq = req.simpleFooRequest().findSimpleFooById(
+        999L).with("selfOneToManyField");
     fooReq.fire(new Receiver<SimpleFooProxy>() {
       public void onSuccess(final SimpleFooProxy fooProxy) {
-         final Request<String> procReq = req.simpleFooRequest().processList(
-             fooProxy, fooProxy.getSelfOneToManyField());
-         procReq.fire(new Receiver<String>() {
-           @Override
-           public void onSuccess(String response) {
-             assertEquals(fooProxy.getUserName(), response);
-             finishTestAndReset();
-           }
-         });
+        final Request<String> procReq = req.simpleFooRequest().processList(
+            fooProxy, fooProxy.getSelfOneToManyField());
+        procReq.fire(new Receiver<String>() {
+          @Override
+          public void onSuccess(String response) {
+            assertEquals(fooProxy.getUserName(), response);
+            finishTestAndReset();
+          }
+        });
       }
     });
   }
 
-  
   public void testProxysAsInstanceMethodParams() {
     delayTestFinish(5000);
     req.simpleFooRequest().findSimpleFooById(999L).fire(
@@ -1176,8 +1241,8 @@
           @Override
           public void onSuccess(SimpleFooProxy response) {
             SimpleBarProxy bar = req.create(SimpleBarProxy.class);
-            Request<String> helloReq = req.simpleFooRequest().hello(
-                response, bar);
+            Request<String> helloReq = req.simpleFooRequest().hello(response,
+                bar);
             bar = helloReq.edit(bar);
             bar.setUserName("BAR");
             helloReq.fire(new Receiver<String>() {
@@ -1190,28 +1255,116 @@
           }
         });
   }
-  
+
   public void testServerFailureCheckedException() {
     SimpleFooProxy newFoo = req.create(SimpleFooProxy.class);
-    final Request<SimpleFooProxy> persistRequest =
-      req.simpleFooRequest().persistAndReturnSelf(newFoo);
+    final Request<SimpleFooProxy> persistRequest = req.simpleFooRequest().persistAndReturnSelf(
+        newFoo);
     final SimpleFooProxy mutableFoo = persistRequest.edit(newFoo);
     // 43 is the crash causing magic number for a checked exception
     mutableFoo.setPleaseCrash(43);
     persistRequest.fire(new FooReciever(mutableFoo, persistRequest, ""));
   }
-  
+
   public void testServerFailureRuntimeException() {
     delayTestFinish(5000);
     SimpleFooProxy newFoo = req.create(SimpleFooProxy.class);
-    final Request<SimpleFooProxy> persistRequest = 
-      req.simpleFooRequest().persistAndReturnSelf(newFoo);
+    final Request<SimpleFooProxy> persistRequest = req.simpleFooRequest().persistAndReturnSelf(
+        newFoo);
     final SimpleFooProxy mutableFoo = persistRequest.edit(newFoo);
     // 42 is the crash causing magic number for a runtime exception
-    mutableFoo.setPleaseCrash(42); 
+    mutableFoo.setPleaseCrash(42);
     persistRequest.fire(new FooReciever(mutableFoo, persistRequest, ""));
-  }    
-   
+  }
+
+  /**
+   * Tests the behaviors of setters and their effects on getters.
+   */
+  public void testSetters() {
+    SimpleFooProxy foo = req.create(SimpleFooProxy.class);
+    SimpleBarProxy bar = req.create(SimpleBarProxy.class);
+
+    // Assert that uninitalize references are null
+    assertNull(foo.getBarField());
+
+    // Assert that objects must be made mutable before calling setters.
+    try {
+      foo.setBarField(bar);
+      fail("Must require request to call setters");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Request<SimpleFooProxy> r = req.simpleFooRequest().persistAndReturnSelf(foo);
+    foo = r.edit(foo);
+    foo.setBarField(bar);
+
+    // Assert that the set value is retained
+    SimpleBarProxy returnedBarField = foo.getBarField();
+    assertNotNull(returnedBarField);
+    assertEquals(bar.stableId(), returnedBarField.stableId());
+    assertEquals(returnedBarField, foo.getBarField());
+    assertNotSame(returnedBarField, foo.getBarField());
+
+    // Returned not equal to original because it's associated with a request
+    assertFalse(bar.equals(returnedBarField));
+
+    // Getters called on mutable objects are also mutable
+    returnedBarField.setUserName("userName");
+    assertEquals("userName", returnedBarField.getUserName());
+  }
+
+  /**
+   * There's plenty of special-case code for Collection properties, so they need
+   * to be tested as well.
+   */
+  public void testSettersWithCollections() {
+    SimpleFooProxy foo = req.create(SimpleFooProxy.class);
+    SimpleBarProxy bar = req.create(SimpleBarProxy.class);
+    List<SimpleBarProxy> originalList = Collections.singletonList(bar);
+
+    // Assert that uninitalize references are null
+    assertNull(foo.getOneToManyField());
+
+    // Assert that objects must be made mutable before calling setters.
+    try {
+      foo.setOneToManyField(null);
+      fail("Must require request to call setters");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Request<SimpleFooProxy> r = req.simpleFooRequest().persistAndReturnSelf(foo);
+    foo = r.edit(foo);
+    foo.setOneToManyField(originalList);
+    // There's a "dummy" create case here; AbstractRequest, DVS is untestable
+
+    // Assert that the value is retained, but a defensive copy
+    List<SimpleBarProxy> list = foo.getOneToManyField();
+    assertNotSame(originalList, list);
+    // Not equal because list is associated with a request now
+    assertFalse(originalList.equals(list));
+    assertEquals(1, list.size());
+    assertEquals(bar.stableId(), list.get(0).stableId());
+    assertEquals(list, foo.getOneToManyField());
+
+    // Assert that entities returned from editable list are mutable
+    list.get(0).setUserName("userName");
+  }
+
+  public void testSettersWithMutableObject() {
+    SimpleFooProxy foo = req.create(SimpleFooProxy.class);
+    Request<SimpleFooProxy> r = req.simpleFooRequest().persistAndReturnSelf(foo);
+    foo = r.edit(foo);
+
+    SimpleBarProxy immutableBar = req.create(SimpleBarProxy.class);
+    SimpleBarProxy mutableBar = r.edit(immutableBar);
+    mutableBar.setUserName("userName");
+    foo.setBarField(mutableBar);
+
+    // Creating a new editable object in the same request should read through
+    r.edit(immutableBar).setUserName("Reset");
+    assertEquals("Reset", foo.getBarField().getUserName());
+  }
+
   public void testStableId() {
     delayTestFinish(5000);
 
@@ -1311,8 +1464,7 @@
     fooCreationRequest().fire(new Receiver<SimpleFooProxy>() {
       @Override
       public void onSuccess(SimpleFooProxy returned) {
-        Request<Void> editRequest = req.simpleFooRequest().persist(
-            returned);
+        Request<Void> editRequest = req.simpleFooRequest().persist(returned);
         new FailFixAndRefire<Void>(returned, editRequest).doVoidTest();
       }
     });
diff --git a/user/test/com/google/gwt/requestfactory/client/SimpleRequestFactoryInstance.java b/user/test/com/google/gwt/requestfactory/client/SimpleRequestFactoryInstance.java
index 2dded39..2889db8 100644
--- a/user/test/com/google/gwt/requestfactory/client/SimpleRequestFactoryInstance.java
+++ b/user/test/com/google/gwt/requestfactory/client/SimpleRequestFactoryInstance.java
@@ -16,6 +16,7 @@
 package com.google.gwt.requestfactory.client;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.SimpleEventBus;
 import com.google.gwt.requestfactory.client.impl.ProxyImpl;
 import com.google.gwt.requestfactory.client.impl.ProxySchema;
 import com.google.gwt.requestfactory.client.impl.RequestFactoryJsonImpl;
@@ -31,6 +32,7 @@
   public static SimpleRequestFactory factory() {
     if (factory == null) {
       factory = GWT.create(SimpleRequestFactory.class);
+      factory.initialize(new SimpleEventBus());
     }
 
     return factory;
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
index 3b6ebc2..f6e2fd6 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
@@ -34,11 +34,15 @@
    * DO NOT USE THIS UGLY HACK DIRECTLY! Call {@link #get} instead.
    */
   private static Map<String, SimpleBar> jreTestSingleton = new HashMap<String, SimpleBar>();
- 
+
   private static long nextId = 2L;
 
+  static {
+    reset();
+  }
+
   public static Long countSimpleBar() {
-      return (long) get().size();
+    return (long) get().size();
   }
 
   public static List<SimpleBar> findAll() {
@@ -53,8 +57,12 @@
     return findSimpleBarById(id);
   }
 
+  /**
+   * Returns <code>null</code> if {@link #findFails} is <code>true</code>.
+   */
   public static SimpleBar findSimpleBarById(String id) {
-    return get().get(id);
+    SimpleBar toReturn = get().get(id);
+    return toReturn.findFails ? null : toReturn;
   }
 
   @SuppressWarnings("unchecked")
@@ -82,6 +90,11 @@
     return findSimpleBar("1L");
   }
 
+  public static SimpleBar returnFirst(List<SimpleBar> list) {
+    SimpleBar toReturn = list.get(0);
+    return toReturn;
+  }
+
   public static synchronized Map<String, SimpleBar> reset() {
     Map<String, SimpleBar> instance = new HashMap<String, SimpleBar>();
     // fixtures
@@ -105,24 +118,23 @@
     return instance;
   }
 
-  static {
-    reset();
-  }
-
   Integer version = 1;
 
   @Id
   private String id = "999L";
-
-  private String userName;
-
+  private boolean findFails;
   private boolean isNew = true;
+  private String userName;
 
   public SimpleBar() {
     version = 1;
     userName = "FOO";
   }
 
+  public Boolean getFindFails() {
+    return findFails;
+  }
+
   public String getId() {
     return id;
   }
@@ -148,6 +160,10 @@
     return this;
   }
 
+  public void setFindFails(Boolean fails) {
+    this.findFails = fails;
+  }
+
   public void setId(String id) {
     this.id = id;
   }
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index 15f8edf..23c56d2 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -105,7 +105,7 @@
   public static Date processDateList(List<Date> values) {
     return values.get(0);
   }
-  
+
   public static SimpleEnum processEnumList(List<SimpleEnum> values) {
     return values.get(0);
   }
@@ -126,6 +126,18 @@
     return instance;
   }
 
+  public static List<SimpleFoo> returnNullList() {
+    return null;
+  }
+
+  public static SimpleFoo returnNullSimpleFoo() {
+    return null;
+  }
+
+  public static String returnNullString() {
+    return null;
+  }
+
   @SuppressWarnings("unused")
   private static Integer privateMethod() {
     return 0;
@@ -171,7 +183,7 @@
   private List<SimpleBar> oneToManyField;
   private List<SimpleFoo> selfOneToManyField;
   private Set<SimpleBar> oneToManySetField;
-  
+
   private List<Integer> numberListField;
 
   public SimpleFoo() {
@@ -284,7 +296,7 @@
   public String getNullField() {
     return nullField;
   }
-  
+
   public List<Integer> getNumberListField() {
     return numberListField;
   }
@@ -351,7 +363,7 @@
     }
     return result;
   }
-  
+
   public void setBarField(SimpleBar barField) {
     this.barField = barField;
   }
@@ -459,7 +471,8 @@
 
   public void setPleaseCrash(Integer crashIf42or43) throws Exception {
     if (crashIf42or43 == 42) {
-      throw new UnsupportedOperationException("THIS EXCEPTION IS EXPECTED BY A TEST");
+      throw new UnsupportedOperationException(
+          "THIS EXCEPTION IS EXPECTED BY A TEST");
     }
     if (crashIf42or43 == 43) {
       throw new Exception("THIS EXCEPTION IS EXPECTED BY A TEST");
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java b/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java
index 892f926..782ea66 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java
@@ -18,15 +18,19 @@
 import com.google.gwt.requestfactory.server.SimpleBar;
 
 /**
- * A simple entity used for testing. Has an int field and date field. Add other data types as their
- * support gets built in.
+ * A simple entity used for testing. Has an int field and date field. Add other
+ * data types as their support gets built in.
  */
 @ProxyFor(SimpleBar.class)
 public interface SimpleBarProxy extends EntityProxy {
+  Boolean getFindFails();
+
   String getId();
-  
+
   String getUserName();
 
+  void setFindFails(Boolean fails);
+
   void setUserName(String userName);
 
   EntityProxyId<SimpleBarProxy> stableId();
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleBarRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleBarRequest.java
index 19888eb..51d4879 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleBarRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleBarRequest.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.requestfactory.shared;
 
+import java.util.List;
+
 /**
  * Do nothing test interface.
  */
@@ -36,4 +38,6 @@
   ProxyRequest<SimpleBarProxy> persistAndReturnSelf(SimpleBarProxy proxy);
 
   Request<Void> reset();
+
+  ProxyRequest<SimpleBarProxy> returnFirst(List<SimpleBarProxy> proxy);
 }
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index d482096..c9aa77b 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -61,6 +61,12 @@
   
   Request<Void> reset();
 
+  ProxyListRequest<SimpleFooProxy> returnNullList();
+
+  ProxyRequest<SimpleFooProxy> returnNullSimpleFoo();
+
+  Request<String> returnNullString();
+
   @Instance
   Request<Integer> sum(SimpleFooProxy instance, List<Integer> values);
 }