Merging releases/1.5 into trunk

svn merge -r3505:3549 https://google-web-toolkit.googlecode.com/svn/releases/1.5 .



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3589 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index 726d7f4..01800bc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -1240,7 +1240,7 @@
       for (JStatement statement : body.statements) {
         if (statement instanceof JCaseStatement) {
           potentialNoOpCaseStatements.add(statement);
-        } else if (isUnconditionalBreak(statement)) {
+        } else if (isUnconditionalUnlabeledBreak(statement)) {
           // If we have any potential no-ops, they now become real no-ops.
           noOpCaseStatements.addAll(potentialNoOpCaseStatements);
           potentialNoOpCaseStatements.clear();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index 4f9a305..b284fad 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -189,6 +189,8 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
+import java.util.TreeSet;
 
 /**
  * This is the big kahuna where most of the nitty gritty of creating our AST
@@ -2553,7 +2555,7 @@
           return null;
         } else {
           // look for a method
-          String almostMatches = null;
+          TreeSet<String> almostMatches = new TreeSet<String>();
           String methodName = parsed.memberName();
           String jsniSig = parsed.memberSignature();
           if (type == null) {
@@ -2561,31 +2563,44 @@
               return program.getNullMethod();
             }
           } else {
-            for (int i = 0; i < type.methods.size(); ++i) {
-              JMethod method = type.methods.get(i);
-              if (method.getName().equals(methodName)) {
-                String sig = JProgram.getJsniSig(method);
-                if (sig.equals(jsniSig)) {
-                  return method;
-                } else if (almostMatches == null) {
-                  almostMatches = "'" + sig + "'";
-                } else {
-                  almostMatches += ", '" + sig + "'";
+            Queue<JReferenceType> workList = new LinkedList<JReferenceType>();
+            workList.add(type);
+            while (!workList.isEmpty()) {
+              JReferenceType cur = workList.poll();
+              for (int i = 0; i < cur.methods.size(); ++i) {
+                JMethod method = cur.methods.get(i);
+                if (method.getName().equals(methodName)) {
+                  String sig = JProgram.getJsniSig(method);
+                  if (sig.equals(jsniSig)) {
+                    return method;
+                  } else {
+                    almostMatches.add(sig);
+                  }
                 }
               }
+              if (cur.extnds != null) {
+                workList.add(cur.extnds);
+              }
+              workList.addAll(cur.implments);
             }
           }
 
-          if (almostMatches == null) {
+          if (almostMatches.isEmpty()) {
             reportJsniError(info, methodDecl,
                 "Unresolvable native reference to method '" + methodName
                     + "' in type '" + className + "'");
             return null;
           } else {
+            StringBuilder suggestList = new StringBuilder();
+            String comma = "";
+            for (String almost : almostMatches) {
+              suggestList.append(comma + "'" + almost + "'");
+              comma = ", ";
+            }
             reportJsniError(info, methodDecl,
                 "Unresolvable native reference to method '" + methodName
                     + "' in type '" + className + "' (did you mean "
-                    + almostMatches + "?)");
+                    + suggestList.toString() + "?)");
             return null;
           }
         }
@@ -2638,7 +2653,8 @@
 
       private void processMethod(JsNameRef nameRef, SourceInfo info,
           JMethod method, JsContext<JsExpression> ctx) {
-        if (method.getEnclosingType() != null) {
+        JReferenceType enclosingType = method.getEnclosingType();
+        if (enclosingType != null) {
           if (method.isStatic() && nameRef.getQualifier() != null) {
             reportJsniError(info, methodDecl,
                 "Cannot make a qualified reference to the static method "
@@ -2647,6 +2663,16 @@
             reportJsniError(info, methodDecl,
                 "Cannot make an unqualified reference to the instance method "
                     + method.getName());
+          } else if (!method.isStatic()
+              && program.isJavaScriptObject(enclosingType)) {
+            reportJsniError(
+                info,
+                methodDecl,
+                "Illegal reference to instance method '"
+                    + method.getName()
+                    + "' in type '"
+                    + enclosingType.getName()
+                    + "', which is an overlay type; only static references to overlay types are allowed from JSNI");
           }
         }
         if (ctx.isLvalue()) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
index 9c401c5..a17dbc4 100644
--- a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
+++ b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
@@ -63,9 +63,11 @@
   }
 
   private void addMember(Member member, String sig) {
-    memberById.add(member);
-    int index = memberById.size() - 1;
-    memberIdByName.put(sig, new Integer(index));
+    if (!memberIdByName.containsKey(sig)) {
+      memberById.add(member);
+      int index = memberById.size() - 1;
+      memberIdByName.put(sig, new Integer(index));
+    }
   }
 
   private String getJsniSignature(Member member) {
@@ -151,6 +153,9 @@
     if (superclass != null) {
       lazyInitTargetMembersUsingReflectionHelper(superclass, false);
     }
+    for (Class<?> intf : targetClass.getInterfaces()) {
+      lazyInitTargetMembersUsingReflectionHelper(intf, false);
+    }
 
     if (addConstructors) {
       Constructor<?>[] constructors = targetClass.getDeclaredConstructors();
diff --git a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
index 022713c..0ebbe02 100644
--- a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
@@ -44,7 +44,6 @@
 import java.net.ServerSocket;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
diff --git a/user/javadoc/com/google/gwt/examples/HistoryExample.java b/user/javadoc/com/google/gwt/examples/HistoryExample.java
index dbe83f9..99f3d0f 100644
--- a/user/javadoc/com/google/gwt/examples/HistoryExample.java
+++ b/user/javadoc/com/google/gwt/examples/HistoryExample.java
@@ -33,15 +33,12 @@
     Hyperlink link1 = new Hyperlink("link to bar", "bar");
     Hyperlink link2 = new Hyperlink("link to baz", "baz");
 
-    // If the application starts with no history token, start it off in the
+    // If the application starts with no history token, redirect to a new
     // 'baz' state.
     String initToken = History.getToken();
-    if (initToken.length() == 0)
-      initToken = "baz";
-
-    // onHistoryChanged() is not called when the application first runs. Call
-    // it now in order to reflect the initial state.
-    onHistoryChanged(initToken);
+    if (initToken.length() == 0) {
+      History.newItem("baz");
+    }
 
     // Add widgets to the root panel.
     VerticalPanel panel = new VerticalPanel();
@@ -53,6 +50,9 @@
 
     // Add history listener
     History.addHistoryListener(this);
+
+    // Now that we've setup our listener, fire the initial history state.
+    History.fireCurrentHistoryState();
   }
 
   public void onHistoryChanged(String historyToken) {
diff --git a/user/src/com/google/gwt/core/client/JavaScriptException.java b/user/src/com/google/gwt/core/client/JavaScriptException.java
index b4e45d7..8bb9b72 100644
--- a/user/src/com/google/gwt/core/client/JavaScriptException.java
+++ b/user/src/com/google/gwt/core/client/JavaScriptException.java
@@ -62,10 +62,18 @@
    */
   private static native String getProperties0(JavaScriptObject e) /*-{
     var result = "";
-    for (prop in e) {
-      if (prop != "name" && prop != "message") {
-        result += "\n " + prop + ": " + e[prop];
+    try {
+      for (prop in e) {
+        if (prop != "name" && prop != "message" && prop != "toString") {
+          try {
+            result += "\n " + prop + ": " + e[prop];
+          } catch (ignored) {
+            // Skip the property if it threw an exception.
+          }
+        }
       }
+    } catch (ignored) {
+      // If we can't do "in" on the exception, just return what we have.
     }
     return result;
   }-*/;
diff --git a/user/src/com/google/gwt/dom/client/HeadingElement.java b/user/src/com/google/gwt/dom/client/HeadingElement.java
index 45030b8..a21532f 100644
--- a/user/src/com/google/gwt/dom/client/HeadingElement.java
+++ b/user/src/com/google/gwt/dom/client/HeadingElement.java
@@ -48,7 +48,7 @@
       assert tag.length() == 2;
       assert tag.charAt(0) == 'h';
 
-      int n = Integer.parseInt(tag.substring(1, 1));
+      int n = Integer.parseInt(tag.substring(1, 2));
       assert (n >= 1) && (n <= 6);
     }
 
diff --git a/user/src/com/google/gwt/user/RemoteService.gwt.xml b/user/src/com/google/gwt/user/RemoteService.gwt.xml
index e03d3c4..2c9a680 100644
--- a/user/src/com/google/gwt/user/RemoteService.gwt.xml
+++ b/user/src/com/google/gwt/user/RemoteService.gwt.xml
@@ -31,19 +31,11 @@
 	<!-- 
 		Declare a property to determine whether warnings for final instance 
 		fields should be suppressed.
-		
-		NOTE: We no longer emit warnings for final fields.  This property has 
-		been deprecated, is currently being ignored, and will be removed in a 
-		future version of GWT.
 	-->
 	<define-property name="gwt.suppressNonStaticFinalFieldWarnings" values="true,false" />
 	
 	<!-- 
 	    Default warning for non-static, final fields enabled 
-
-		NOTE: We no longer emit a warning for final fields.  This property has 
-		been deprecated, is currently being ignored, and will be removed in a 
-		future version of GWT.
 	-->
 	<set-property name="gwt.suppressNonStaticFinalFieldWarnings" value="false" />
 
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index f931cbe..b7865d5 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -401,14 +401,8 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if ALT was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static boolean eventGetAltKey(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.KEYEVENTS | Event.ONCONTEXTMENU, "altKey");
+  public static boolean eventGetAltKey(Event evt) {
     return impl.eventGetAltKey(evt);
   }
 
@@ -418,11 +412,8 @@
    * @param evt the event to be tested
    * @return a bit-field, defined by {@link Event#BUTTON_LEFT},
    *         {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEDOWN} or {@link Event#ONMOUSEUP}
    */
-  public static int eventGetButton(Event evt) throws AssertionError {
-    assertEventType(evt, Event.ONMOUSEDOWN | Event.ONMOUSEUP, "button");
+  public static int eventGetButton(Event evt) {
     return impl.eventGetButton(evt);
   }
 
@@ -431,14 +422,8 @@
    * 
    * @param evt the event to be tested
    * @return the mouse x-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#ONMOUSEWHEEL}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static int eventGetClientX(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.ONMOUSEWHEEL | Event.ONCONTEXTMENU, "clientX");
+  public static int eventGetClientX(Event evt) {
     return impl.eventGetClientX(evt);
   }
 
@@ -447,14 +432,8 @@
    * 
    * @param evt the event to be tested
    * @return the mouse y-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#ONMOUSEWHEEL}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static int eventGetClientY(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.ONMOUSEWHEEL | Event.ONCONTEXTMENU, "clientY");
+  public static int eventGetClientY(Event evt) {
     return impl.eventGetClientY(evt);
   }
 
@@ -463,14 +442,8 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if CTRL was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static boolean eventGetCtrlKey(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.KEYEVENTS | Event.ONCONTEXTMENU, "ctrlKey");
+  public static boolean eventGetCtrlKey(Event evt) {
     return impl.eventGetCtrlKey(evt);
   }
 
@@ -503,11 +476,8 @@
    * 
    * @param evt the event to be tested
    * @return the element from which the mouse pointer was moved
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEOVER} or {@link Event#ONMOUSEOUT}
    */
-  public static Element eventGetFromElement(Event evt) throws AssertionError {
-    assertEventType(evt, Event.ONMOUSEOVER | Event.ONMOUSEOUT, "fromElement");
+  public static Element eventGetFromElement(Event evt) {
     return impl.eventGetFromElement(evt);
   }
 
@@ -522,11 +492,9 @@
    * 
    * @param evt the event to be tested
    * @return the Unicode character or key code.
-   * @throws AssertionError if event type is not one of {@link Event#KEYEVENTS}
    * @see com.google.gwt.user.client.ui.KeyboardListener
    */
-  public static int eventGetKeyCode(Event evt) throws AssertionError {
-    assertEventType(evt, Event.KEYEVENTS, "keyCode");
+  public static int eventGetKeyCode(Event evt) {
     return impl.eventGetKeyCode(evt);
   }
 
@@ -535,14 +503,8 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if META was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static boolean eventGetMetaKey(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.KEYEVENTS | Event.ONCONTEXTMENU, "metaKey");
+  public static boolean eventGetMetaKey(Event evt) {
     return impl.eventGetMetaKey(evt);
   }
 
@@ -560,11 +522,8 @@
    * 
    * @param evt the event to be examined.
    * @return The velocity of the mouse wheel.
-   * @throws AssertionError if event type is not {@link Event#ONMOUSEWHEEL}
    */
-  public static int eventGetMouseWheelVelocityY(Event evt)
-      throws AssertionError {
-    assertEventType(evt, Event.ONMOUSEWHEEL, "mouseWheelVelocityY");
+  public static int eventGetMouseWheelVelocityY(Event evt) {
     return impl.eventGetMouseWheelVelocityY(evt);
   }
 
@@ -573,10 +532,8 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if this key event was an auto-repeat
-   * @throws AssertionError if event type is not {@link Event#ONKEYDOWN}
    */
-  public static boolean eventGetRepeat(Event evt) throws AssertionError {
-    assertEventType(evt, Event.ONKEYDOWN, "repeat");
+  public static boolean eventGetRepeat(Event evt) {
     return impl.eventGetRepeat(evt);
   }
 
@@ -585,14 +542,8 @@
    * 
    * @param evt the event to be tested
    * @return the mouse x-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONMOUSEWHEEL},
-   *           {@link Event#ONCLICK}, {@link Event#ONDBLCLICK}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static int eventGetScreenX(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.ONCLICK
-        | Event.ONDBLCLICK | Event.ONCONTEXTMENU, "screenX");
+  public static int eventGetScreenX(Event evt) {
     return impl.eventGetScreenX(evt);
   }
 
@@ -601,14 +552,8 @@
    * 
    * @param evt the event to be tested
    * @return the mouse y-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONMOUSEWHEEL},
-   *           {@link Event#ONCLICK}, {@link Event#ONDBLCLICK}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static int eventGetScreenY(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.ONCLICK
-        | Event.ONDBLCLICK | Event.ONCONTEXTMENU, "screenY");
+  public static int eventGetScreenY(Event evt) {
     return impl.eventGetScreenY(evt);
   }
 
@@ -617,14 +562,8 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if shift was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public static boolean eventGetShiftKey(Event evt) throws AssertionError {
-    assertEventType(evt, Event.MOUSEEVENTS | Event.ONCLICK | Event.ONDBLCLICK
-        | Event.KEYEVENTS | Event.ONCONTEXTMENU, "shiftKey");
+  public static boolean eventGetShiftKey(Event evt) {
     return impl.eventGetShiftKey(evt);
   }
 
@@ -644,11 +583,8 @@
    * 
    * @param evt the event to be tested
    * @return the element to which the mouse pointer was moved
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEOVER} or {@link Event#ONMOUSEOUT}
    */
-  public static Element eventGetToElement(Event evt) throws AssertionError {
-    assertEventType(evt, Event.ONMOUSEOVER | Event.ONMOUSEOUT, "toElement");
+  public static Element eventGetToElement(Event evt) {
     return impl.eventGetToElement(evt);
   }
 
@@ -686,10 +622,8 @@
    * 
    * @param evt the event whose key code is to be set
    * @param key the new key code
-   * @throws AssertionError if event type is not one of {@link Event#KEYEVENTS}
    */
-  public static void eventSetKeyCode(Event evt, char key) throws AssertionError {
-    assertEventType(evt, Event.KEYEVENTS, "keyCode");
+  public static void eventSetKeyCode(Event evt, char key) {
     impl.eventSetKeyCode(evt, key);
   }
 
@@ -1347,20 +1281,6 @@
     return ret;
   }
 
-  /**
-   * Assert that the event is of the given event type, as defined by the
-   * {@link Event} class.
-   * 
-   * @param evt the {@link Event} to check
-   * @param evtType the event type that is expected
-   * @param attr the attribute that should be defined by the event
-   */
-  private static void assertEventType(Event evt, int evtType, String attr) {
-    assert (eventGetType(evt) & evtType) != 0 :
-      "attribute '" + attr + "' not defined for event type '"
-      + eventGetTypeString(evt) + "'";
-  }
-
   private static void dispatchEventAndCatch(Event evt, Element elem,
       EventListener listener, UncaughtExceptionHandler handler) {
     try {
diff --git a/user/src/com/google/gwt/user/client/History.java b/user/src/com/google/gwt/user/client/History.java
index ff8d1e6..d3e0612 100644
--- a/user/src/com/google/gwt/user/client/History.java
+++ b/user/src/com/google/gwt/user/client/History.java
@@ -40,10 +40,10 @@
  * <p>
  * <h3>URL Encoding</h3>
  * Any valid characters may be used in the history token and will survive
- * round-trips through newItem to getToken()/onHistoryChanged(), but most will
- * be encoded in the user-visible URL. The following US-ASCII characters are not
- * encoded on any currently supported browser (but may be in the future due to
- * future browser changes):
+ * round-trips through {@link #newItem(String)} to {@link #getToken()}/{@link HistoryListener#onHistoryChanged(String)},
+ * but most will be encoded in the user-visible URL. The following US-ASCII
+ * characters are not encoded on any currently supported browser (but may be in
+ * the future due to future browser changes):
  * <ul>
  * <li>a-z
  * <li>A-Z
@@ -63,12 +63,11 @@
       impl = null;
 
       // Tell the user.
-      GWT.log(
-          "Unable to initialize the history subsystem; did you "
-              + "include the history frame in your host page? Try "
-              + "<iframe src=\"javascript:''\" id='__gwt_historyFrame' "
-              + "style='position:absolute;width:0;height:0;border:0'>"
-              + "</iframe>", null);
+      GWT.log("Unable to initialize the history subsystem; did you "
+          + "include the history frame in your host page? Try "
+          + "<iframe src=\"javascript:''\" id='__gwt_historyFrame' "
+          + "style='position:absolute;width:0;height:0;border:0'>"
+          + "</iframe>", null);
     }
   }
 
@@ -91,6 +90,16 @@
   }-*/;
 
   /**
+   * Fire {@link HistoryListener#onHistoryChanged(String)} events with the
+   * current history state. This is most often called at the end of an
+   * application's {@link com.google.gwt.core.client.EntryPoint#onModuleLoad()}
+   * to inform history listeners of the initial application state.
+   */
+  public static void fireCurrentHistoryState() {
+    HistoryImpl.fireHistoryChangedImpl(getToken());
+  }
+
+  /**
    * Programmatic equivalent to the user pressing the browser's 'forward'
    * button.
    */
@@ -99,11 +108,11 @@
   }-*/;
 
   /**
-   * Gets the current history token. The listener will not receive an
-   * onHistoryChanged() event for the initial token; requiring that an
-   * application request the token explicitly on startup gives it an opportunity
-   * to run different initialization code in the presence or absence of an
-   * initial token.
+   * Gets the current history token. The listener will not receive a
+   * {@link HistoryListener#onHistoryChanged(String)} event for the initial
+   * token; requiring that an application request the token explicitly on
+   * startup gives it an opportunity to run different initialization code in the
+   * presence or absence of an initial token.
    * 
    * @return the initial token, or the empty string if none is present.
    */
@@ -114,8 +123,8 @@
   /**
    * Adds a new browser history entry. In hosted mode, the 'back' and 'forward'
    * actions are accessible via the standard Alt-Left and Alt-Right keystrokes.
-   * Calling this method will cause {@link HistoryListener#onHistoryChanged} to
-   * be called as well.
+   * Calling this method will cause
+   * {@link HistoryListener#onHistoryChanged(String)} to be called as well.
    * 
    * @param historyToken the token to associate with the new history item
    */
@@ -126,11 +135,14 @@
   /**
    * Adds a new browser history entry. In hosted mode, the 'back' and 'forward'
    * actions are accessible via the standard Alt-Left and Alt-Right keystrokes.
-   * Calling this method will cause {@link HistoryListener#onHistoryChanged} to
-   * be called as well if and only if issueEvent is true.
+   * Calling this method will cause
+   * {@link HistoryListener#onHistoryChanged(String)} to be called as well if
+   * and only if issueEvent is true.
    * 
    * @param historyToken the token to associate with the new history item
-   * @param issueEvent true if an onHistoryChanged event should be issued
+   * @param issueEvent true if a
+   *          {@link HistoryListener#onHistoryChanged(String)} event should be
+   *          issued
    */
   public static void newItem(String historyToken, boolean issueEvent) {
     if (impl != null) {
@@ -139,6 +151,22 @@
   }
 
   /**
+   * Call all history listeners with the specified token. Note that this does
+   * not change the history system's idea of the current state and is only kept
+   * for backward compatibility. To fire history events for the initial state of
+   * the application, instead call {@link #fireCurrentHistoryState()} from the
+   * application {@link com.google.gwt.core.client.EntryPoint#onModuleLoad()}
+   * method.
+   * 
+   * @param historyToken history token to fire events for
+   * @deprecated Use {@link #fireCurrentHistoryState()} instead.
+   */
+  @Deprecated
+  public static void onHistoryChanged(String historyToken) {
+    HistoryImpl.fireHistoryChangedImpl(historyToken);
+  }
+
+  /**
    * Removes a history listener.
    * 
    * @param listener the listener to be removed
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 58e270f..d22e2ff 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -366,7 +366,7 @@
   /**
    * Opens a new browser window. The "name" and "features" arguments are
    * specified <a href=
-   * 'http://www.mozilla.org/docs/dom/domref/dom_window_ref76.html'>here</a>.
+   * 'http://developer.mozilla.org/en/docs/DOM:window.open'>here</a>.
    * 
    * @param url the URL that the new window will display
    * @param name the name of the window (e.g. "_blank")
diff --git a/user/src/com/google/gwt/user/client/impl/HistoryImpl.java b/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
index a16ef2a..a1a1147 100644
--- a/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/HistoryImpl.java
@@ -40,6 +40,23 @@
     historyListeners.add(listener);
   }
 
+  /**
+   * Fires the {@link HistoryListener#onHistoryChanged(String)} event to all
+   * listeners with the given token.
+   */
+  public static void fireHistoryChangedImpl(String historyToken) {
+    // TODO: replace this copy when a more general solution to event handlers
+    // wanting to remove themselves from the listener list is implemented.
+
+    // This is necessary to avoid a CurrentModificationException in hosted
+    // mode, as the listeners may try to remove themselves from the list while
+    // it is being iterated, such as in HistoryTest.
+    HistoryListener[] listenersToInvoke = historyListeners.toArray(new HistoryListener[historyListeners.size()]);
+    for (HistoryListener listener : listenersToInvoke) {
+      listener.onHistoryChanged(historyToken);
+    }
+  }
+
   public static native String getToken() /*-{
     return $wnd.__gwt_historyToken || "";
   }-*/;
@@ -75,19 +92,6 @@
     }
   }
 
-  private static void fireHistoryChangedImpl(String historyToken) {
-    // TODO: replace this copy when a more general solution to event handlers
-    // wanting to remove themselves from the listener list is implemented.
-
-    // This is necessary to avoid a CurrentModificationException in hosted
-    // mode, as the listeners may try to remove themselves from the list while
-    // it is being iterated, such as in HistoryTest.
-    HistoryListener[] listenersToInvoke = historyListeners.toArray(new HistoryListener[historyListeners.size()]);
-    for (HistoryListener listener : listenersToInvoke) {
-      listener.onHistoryChanged(historyToken);
-    }
-  }
-
   public abstract boolean init();
 
   public final void newItem(String historyToken, boolean issueEvent) {
diff --git a/user/src/com/google/gwt/user/client/rpc/AsyncCallback.java b/user/src/com/google/gwt/user/client/rpc/AsyncCallback.java
index ee958d6..67ccdcd 100644
--- a/user/src/com/google/gwt/user/client/rpc/AsyncCallback.java
+++ b/user/src/com/google/gwt/user/client/rpc/AsyncCallback.java
@@ -27,7 +27,8 @@
  * <p>
  * Each callable asynchronous method corresponds to a method in the correlated
  * service interface. The asynchronous method always takes an
- * <code>AsyncCallback</code> as its last parameter.
+ * <code>AsyncCallback&lt;T&gt;</code> as its last parameter, where
+ * <code>T</code> is the return type of the correlated synchronous method.
  * </p>
  * 
  * <p>
@@ -41,7 +42,7 @@
  * Its asynchronous counterpart method be declared as:
  * 
  * <pre>
- * void getShapes(String databaseName, AsyncCallback callback);
+ * void getShapes(String databaseName, AsyncCallback&lt;Shape[]&gt; callback);
  * </pre>
  * 
  * Note that <code>throws</code> declaration is not repeated in the async
@@ -53,11 +54,10 @@
  * this:
  * 
  * <pre class="code">
- * service.getShapes(dbName, new AsyncCallback() {
- *   public void onSuccess(Object result) {
+ * service.getShapes(dbName, new AsyncCallback<Shape[]>() {
+ *   public void onSuccess(Shape[] result) {
  *     // It's always safe to downcast to the known return type. 
- *     Shape[] shapes = (Shape[]) result;
- *     controller.processShapes(shapes);
+ *     controller.processShapes(result);
  *   }
  * 
  *   public void onFailure(Throwable caught) {
@@ -82,7 +82,12 @@
  * 
  * </p>
  * 
- * @param <T>
+ * @param <T> The type of the return value that was declared in the synchronous
+ *          version of the method. If the return type is a primitive, use the
+ *          boxed version of that primitive (for example, an <code>int</code>
+ *          return type becomes an {@link Integer} type argument, and a
+ *          <code>void</code> return type becomes a {@link Void} type
+ *          argument, which is always <code>null</code>).
  */
 public interface AsyncCallback<T> {
 
@@ -103,12 +108,9 @@
   void onFailure(Throwable caught);
 
   /**
-   * Called when an asynchronous call completes successfully. It is always safe
-   * to downcast the parameter (of type <code>Object</code>) to the return
-   * type of the original method for which this is a callback. Note that if the
-   * return type of the synchronous service interface method is a primitive then
-   * the parameter will be the boxed version of the primitive (for example, an
-   * <code>int</code> return type becomes an {@link Integer}.
+   * Called when an asynchronous call completes successfully.
+   * 
+   * @param result the return value of the remote produced call
    */
   void onSuccess(T result);
 }
diff --git a/user/src/com/google/gwt/user/client/ui/DeckPanel.java b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
index 9d65a5d..b0c5e8a 100644
--- a/user/src/com/google/gwt/user/client/ui/DeckPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
@@ -148,10 +148,12 @@
       int deckHeight = deckElem.getOffsetHeight();
       if (growing) {
         fixedHeight = container2.getOffsetHeight();
-        container2.getStyle().setPropertyPx("height", fixedHeight - 1);
+        container2.getStyle().setPropertyPx("height",
+            Math.max(1, fixedHeight - 1));
       } else {
         fixedHeight = container1.getOffsetHeight();
-        container1.getStyle().setPropertyPx("height", fixedHeight - 1);
+        container1.getStyle().setPropertyPx("height",
+            Math.max(1, fixedHeight - 1));
       }
       if (deckElem.getOffsetHeight() != deckHeight) {
         fixedHeight = -1;
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
index a8f599d..26b12a7 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -19,7 +19,6 @@
 import com.google.gwt.core.ext.GeneratorContext;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.linker.GeneratedResource;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JMethod;
 import com.google.gwt.core.ext.typeinfo.JPackage;
@@ -212,7 +211,7 @@
 
     // Determine the set of serializable types
     SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
-        logger, typeOracle);
+        logger, context.getPropertyOracle(), typeOracle);
     try {
       addRequiredRoots(logger, typeOracle, stob);
 
@@ -229,8 +228,9 @@
         serviceIntf.getQualifiedSourceName() + ".rpc.log");
     stob.setLogOutputStream(pathInfo);
     SerializableTypeOracle sto = stob.build(logger);
-    GeneratedResource rpcLog = context.commitResource(logger, pathInfo);
-    rpcLog.setPrivate(true);
+    if (pathInfo != null) {
+      context.commitResource(logger, pathInfo).setPrivate(true);
+    }
 
     TypeSerializerCreator tsc = new TypeSerializerCreator(logger, sto, context,
         sto.getTypeSerializerQualifiedName(serviceIntf));
@@ -346,7 +346,7 @@
     String requestIdName = nameFactory.createName("requestId");
     w.println("int " + requestIdName + " = getNextRequestId();");
 
-    String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName();        
+    String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName();
     String tossName = nameFactory.createName("toss");
     w.println("boolean " + tossName + " = isStatsAvailable() && stats("
         + "timeStat(\"" + statsMethodExpr + "\", getRequestId(), \"begin\"));");
@@ -411,8 +411,8 @@
     w.println("String " + payloadName + " = " + streamWriterName
         + ".toString();");
 
-    w.println(tossName + " = isStatsAvailable() && stats("
-        + "timeStat(\"" + statsMethodExpr + "\", getRequestId(), \"requestSerialized\"));");
+    w.println(tossName + " = isStatsAvailable() && stats(" + "timeStat(\""
+        + statsMethodExpr + "\", getRequestId(), \"requestSerialized\"));");
 
     /*
      * Depending on the return type for the async method, return a
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index f1a9e0b..3bd7a0f 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.rebind.rpc;
 
+import com.google.gwt.core.ext.PropertyOracle;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.TreeLogger.Type;
@@ -452,13 +453,15 @@
    * Returns <code>true</code> if the field qualifies for serialization
    * without considering its type.
    */
-  static boolean shouldConsiderForSerialization(TreeLogger logger, JField field) {
+  static boolean shouldConsiderForSerialization(TreeLogger logger,
+      boolean suppressNonStaticFinalFieldWarnings, JField field) {
     if (field.isStatic() || field.isTransient()) {
       return false;
     }
 
     if (field.isFinal()) {
-      logger.branch(TreeLogger.DEBUG, "Field '" + field.toString()
+      logger.branch(suppressNonStaticFinalFieldWarnings ? TreeLogger.DEBUG
+          : TreeLogger.WARN, "Field '" + field.toString()
           + "' will not be serialized because it is final", null);
       return false;
     }
@@ -577,6 +580,12 @@
 
   private final Map<JClassType, TreeLogger> rootTypes = new LinkedHashMap<JClassType, TreeLogger>();
 
+  /**
+   * If <code>true</code> we will not warn if a serializable type contains a
+   * non-static final field. We warn because these fields are not serialized.
+   */
+  private final boolean suppressNonStaticFinalFieldWarnings;
+
   private final TypeConstrainer typeConstrainer;
   private TypeFilter typeFilter = DEFAULT_TYPE_FILTER;
 
@@ -602,12 +611,14 @@
    * Constructs a builder.
    * 
    * @param logger
+   * @param propertyOracle
    * @param typeOracle
    * 
    * @throws UnableToCompleteException if we fail to find one of our special
    *           types
    */
-  public SerializableTypeOracleBuilder(TreeLogger logger, TypeOracle typeOracle)
+  public SerializableTypeOracleBuilder(TreeLogger logger,
+      PropertyOracle propertyOracle, TypeOracle typeOracle)
       throws UnableToCompleteException {
     this.typeOracle = typeOracle;
     typeConstrainer = new TypeConstrainer(typeOracle);
@@ -619,6 +630,9 @@
       logger.log(TreeLogger.ERROR, null, e);
       throw new UnableToCompleteException();
     }
+
+    suppressNonStaticFinalFieldWarnings = Shared.shouldSuppressNonStaticFinalFieldWarnings(
+        logger, propertyOracle);
   }
 
   public void addRootType(TreeLogger logger, JType type) {
@@ -907,34 +921,31 @@
         "Analyzing component type:", null);
     Set<JClassType> instantiableTypes = new HashSet<JClassType>();
 
-    boolean succeeded = checkTypeInstantiable(branch, array.getComponentType(),
-        isSpeculative, TypePaths.createArrayComponentPath(array, path),
-        instantiableTypes);
-    if (succeeded && leafClass != null) {
-      TreeLogger covariantArrayLogger = logger.branch(TreeLogger.DEBUG,
-          "Covariant array types");
+    boolean succeeded = checkTypeInstantiable(branch, leafType, isSpeculative,
+        TypePaths.createArrayComponentPath(array, path), instantiableTypes);
+    if (succeeded) {
+      if (leafClass == null) {
+        assert leafType.isPrimitive() != null;
+        markArrayTypesInstantiable(leafType, array.getRank(), path);
+      } else {
+        TreeLogger covariantArrayLogger = logger.branch(TreeLogger.DEBUG,
+            "Covariant array types");
 
-      /*
-       * Compute covariant arrays for arrays of reference types.
-       */
-      for (JClassType instantiableType : TypeHierarchyUtils.getAllTypesBetweenRootTypeAndLeaves(
-          leafClass, instantiableTypes)) {
-        if (!isAccessibleToSerializer(instantiableType)) {
-          // Skip types that are not accessible from a serializer
-          continue;
-        }
+        /*
+         * Compute covariant arrays for arrays of reference types.
+         */
+        for (JClassType instantiableType : TypeHierarchyUtils.getAllTypesBetweenRootTypeAndLeaves(
+            leafClass, instantiableTypes)) {
+          if (!isAccessibleToSerializer(instantiableType)) {
+            // Skip types that are not accessible from a serializer
+            continue;
+          }
 
-        covariantArrayLogger.branch(
-            TreeLogger.DEBUG,
-            getArrayType(typeOracle, array.getRank(), instantiableType).getParameterizedQualifiedSourceName());
+          covariantArrayLogger.branch(
+              TreeLogger.DEBUG,
+              getArrayType(typeOracle, array.getRank(), instantiableType).getParameterizedQualifiedSourceName());
 
-        for (int rank = 1; rank <= array.getRank(); ++rank) {
-          JArrayType covariantArray = getArrayType(typeOracle, rank,
-              instantiableType);
-
-          TypeInfoComputed covariantArrayTic = getTypeInfoComputed(
-              covariantArray, path);
-          covariantArrayTic.setInstantiable(true);
+          markArrayTypesInstantiable(instantiableType, array.getRank(), path);
         }
       }
     }
@@ -973,7 +984,8 @@
               + "' that qualify for serialization", null);
 
       for (JField field : fields) {
-        if (!shouldConsiderForSerialization(localLogger, field)) {
+        if (!shouldConsiderForSerialization(localLogger,
+            suppressNonStaticFinalFieldWarnings, field)) {
           continue;
         }
 
@@ -1101,10 +1113,14 @@
           originalType);
       TypeInfoComputed tic = getTypeInfoComputed(candidate, subtypePath);
       if (tic.isDone()) {
-        anySubtypes |= tic.isInstantiable();
+        if (tic.isInstantiable()) {
+          anySubtypes = true;
+          instSubtypes.add(candidate);
+        }
         continue;
       } else if (tic.isPendingInstantiable()) {
         anySubtypes = true;
+        instSubtypes.add(candidate);
         continue;
       }
       tic.setPendingInstantiable();
@@ -1182,8 +1198,8 @@
       }
     }
 
-    TypePath path = TypePaths.createTypeArgumentPath(parent, baseType, paramIndex,
-        typeArg);
+    TypePath path = TypePaths.createTypeArgumentPath(parent, baseType,
+        paramIndex, typeArg);
     int exposure = getTypeParameterExposure(baseType, paramIndex);
     switch (exposure) {
       case TypeParameterExposureComputer.EXPOSURE_DIRECT: {
@@ -1359,6 +1375,21 @@
     }
   }
 
+  /**
+   * Mark arrays of <code>leafType</code> as instantiable, for arrays of
+   * dimension up to <code>maxRank</code>.
+   */
+  private void markArrayTypesInstantiable(JType leafType, int maxRank,
+      TypePath path) {
+    for (int rank = 1; rank <= maxRank; ++rank) {
+      JArrayType covariantArray = getArrayType(typeOracle, rank, leafType);
+
+      TypeInfoComputed covariantArrayTic = getTypeInfoComputed(covariantArray,
+          path);
+      covariantArrayTic.setInstantiable(true);
+    }
+  }
+
   private boolean maybeInstantiable(TreeLogger logger, JClassType type) {
     boolean success = canBeInstantiated(logger, type, TreeLogger.DEBUG)
         && shouldConsiderFieldsForSerialization(logger, type, true);
diff --git a/user/src/com/google/gwt/user/rebind/rpc/Shared.java b/user/src/com/google/gwt/user/rebind/rpc/Shared.java
index 0154fbb..e5d7992 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/Shared.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/Shared.java
@@ -31,8 +31,13 @@
    * Property used to control whether or not the RPC system will enforce the
    * versioning scheme or not.
    */
-  static final String RPC_PROP_ENFORCE_TYPE_VERSIONING =
-      "gwt.enforceRPCTypeVersioning";
+  static final String RPC_PROP_ENFORCE_TYPE_VERSIONING = "gwt.enforceRPCTypeVersioning";
+
+  /**
+   * Property used to control whether or not the RPC system will emit warnings
+   * when a type has final fields.
+   */
+  private static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS = "gwt.suppressNonStaticFinalFieldWarnings";
 
   /**
    * Capitalizes a name.
@@ -58,19 +63,18 @@
    */
   static boolean shouldEnforceTypeVersioning(TreeLogger logger,
       PropertyOracle propertyOracle) {
-    try {
-      String propVal =
-          propertyOracle.getPropertyValue(logger,
-              RPC_PROP_ENFORCE_TYPE_VERSIONING);
-      if (propVal.equals("false")) {
-        return false;
-      }
-    } catch (BadPropertyValueException e) {
-      // Purposely ignored, because we want to enforce RPC versioning if
-      // the property is not defined.
-    }
-    // Assume type versioning unless the user explicitly turns it off.
-    return true;
+    return getBooleanProperty(logger, propertyOracle,
+        RPC_PROP_ENFORCE_TYPE_VERSIONING, true);
+  }
+
+  /**
+   * Returns <code>true</code> if warnings should not be emitted for final
+   * fields in serializable types.
+   */
+  static boolean shouldSuppressNonStaticFinalFieldWarnings(TreeLogger logger,
+      PropertyOracle propertyOracle) {
+    return getBooleanProperty(logger, propertyOracle,
+        RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS, false);
   }
 
   /**
@@ -123,7 +127,7 @@
     //
     className = className.replace('.', '_');
 
-    return new String[]{packageName, className};
+    return new String[] {packageName, className};
   }
 
   /**
@@ -137,8 +141,21 @@
    */
   static boolean typeNeedsCast(JType type) {
     return type.isPrimitive() == null
-      && !type.getQualifiedSourceName().equals("java.lang.String")
-      && !type.getQualifiedSourceName().equals("java.lang.Object");
+        && !type.getQualifiedSourceName().equals("java.lang.String")
+        && !type.getQualifiedSourceName().equals("java.lang.Object");
+  }
+
+  private static boolean getBooleanProperty(TreeLogger logger,
+      PropertyOracle propertyOracle, String propertyName, boolean defaultValue) {
+    try {
+      String propVal = propertyOracle.getPropertyValue(logger, propertyName);
+      if (propVal != null && propVal.length() > 0) {
+        return Boolean.valueOf(propVal);
+      }
+    } catch (BadPropertyValueException e) {
+      // Just return the default value.
+    }
+    return defaultValue;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeParameterExposureComputer.java b/user/src/com/google/gwt/user/rebind/rpc/TypeParameterExposureComputer.java
index e3a2ba4..aab0345 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeParameterExposureComputer.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeParameterExposureComputer.java
@@ -87,7 +87,7 @@
           JField[] fields = type.getFields();
           for (JField field : fields) {
             if (!SerializableTypeOracleBuilder.shouldConsiderForSerialization(
-                TreeLogger.NULL, field)) {
+                TreeLogger.NULL, true, field)) {
               continue;
             }
 
@@ -271,7 +271,7 @@
           JField[] fields = type.getFields();
           for (JField field : fields) {
             if (!SerializableTypeOracleBuilder.shouldConsiderForSerialization(
-                TreeLogger.NULL, field)) {
+                TreeLogger.NULL, true, field)) {
               continue;
             }
 
diff --git a/user/src/com/google/gwt/user/server/rpc/RPCServletUtils.java b/user/src/com/google/gwt/user/server/rpc/RPCServletUtils.java
index c020de9..f8e8400 100644
--- a/user/src/com/google/gwt/user/server/rpc/RPCServletUtils.java
+++ b/user/src/com/google/gwt/user/server/rpc/RPCServletUtils.java
@@ -103,43 +103,37 @@
    */
   public static String readContentAsUtf8(HttpServletRequest request)
       throws IOException, ServletException {
+    return readContentAsUtf8(request, true);
+  }
+
+  /**
+   * Returns the content of an {@link HttpServletRequest} by decoding it using
+   * the UTF-8 charset.
+   * 
+   * @param request the servlet request whose content we want to read
+   * @param checkHeaders Specify 'true' to check the Content-Type header to see
+   *          that it matches the expected value 'text/x-gwt-rpc' and the
+   *          content encoding is UTF-8. Disabling this check may allow some
+   *          types of cross type security attacks.
+   * @return the content of an {@link HttpServletRequest} by decoding it using
+   *         the UTF-8 charset
+   * @throws IOException if the requests input stream cannot be accessed, read
+   *           from or closed
+   * @throws ServletException if the content length of the request is not
+   *           specified of if the request's content type is not
+   *           'text/x-gwt-rpc' and 'charset=utf-8'
+   */
+  public static String readContentAsUtf8(HttpServletRequest request,
+      boolean checkHeaders) throws IOException, ServletException {
     int contentLength = request.getContentLength();
     if (contentLength == -1) {
       // Content length must be known.
       throw new ServletException("Content-Length must be specified");
     }
 
-    String contentType = request.getContentType();
-    boolean contentTypeIsOkay = false;
-    // Content-Type must be specified.
-    if (contentType != null) {
-      contentType = contentType.toLowerCase();
-      /*
-       * The Content-Type must be text/x-gwt-rpc.
-       * 
-       * NOTE:We use startsWith because some servlet engines, i.e. Tomcat, do
-       * not remove the charset component but others do.
-       */
-      if (contentType.startsWith(EXPECTED_CONTENT_TYPE)) {
-        String characterEncoding = request.getCharacterEncoding();
-        if (characterEncoding != null) {
-          /*
-           * TODO: It would seem that we should be able to use equalsIgnoreCase
-           * here instead of indexOf. Need to be sure that servlet engines
-           * return a properly parsed character encoding string if we decide to
-           * make this change.
-           */
-          if (characterEncoding.toLowerCase().indexOf(
-              CHARSET_UTF8.toLowerCase()) != -1) {
-            contentTypeIsOkay = true;
-          }
-        }
-      }
-    }
-
-    if (!contentTypeIsOkay) {
-      throw new ServletException("Content-Type must be '"
-          + EXPECTED_CONTENT_TYPE + "' with '" + EXPECTED_CHARSET + "'.");
+    if (checkHeaders) {
+      checkContentType(request);
+      checkCharacterEncoding(request);
     }
 
     InputStream in = request.getInputStream();
@@ -266,6 +260,67 @@
     }
   }
 
+  /**
+   * Performs validation of the character encoding.
+   * 
+   * @param request the incoming request.
+   * @throws ServletException if requests encoding is not UTF-8
+   */
+  private static void checkCharacterEncoding(HttpServletRequest request)
+      throws ServletException {
+    boolean encodingOkay = false;
+    String characterEncoding = request.getCharacterEncoding();
+    if (characterEncoding != null) {
+      /*
+       * TODO: It would seem that we should be able to use equalsIgnoreCase here
+       * instead of indexOf. Need to be sure that servlet engines return a
+       * properly parsed character encoding string if we decide to make this
+       * change.
+       */
+      if (characterEncoding.toLowerCase().indexOf(CHARSET_UTF8.toLowerCase()) != -1) {
+        encodingOkay = true;
+      }
+    }
+
+    if (!encodingOkay) {
+      throw new ServletException("Character Encoding is '"
+          + (characterEncoding == null ? "(null)" : characterEncoding)
+          + "'.  Expected '" + EXPECTED_CHARSET + "'");
+    }
+  }
+
+  /**
+   * Performs Content-Type validation of the incoming request.
+   * 
+   * @param request the incoming request.
+   * @throws ServletException if the request's content type is not
+   *           'text/x-gwt-rpc'
+   */
+  private static void checkContentType(HttpServletRequest request)
+      throws ServletException {
+    String contentType = request.getContentType();
+    boolean contentTypeIsOkay = false;
+
+    if (contentType != null) {
+      contentType = contentType.toLowerCase();
+      /*
+       * The Content-Type must be text/x-gwt-rpc.
+       * 
+       * NOTE:We use startsWith because some servlet engines, i.e. Tomcat, do
+       * not remove the charset component but others do.
+       */
+      if (contentType.startsWith(EXPECTED_CONTENT_TYPE)) {
+        contentTypeIsOkay = true;
+      }
+    }
+
+    if (!contentTypeIsOkay) {
+      throw new ServletException("Content-Type was '"
+          + (contentType == null ? "(null)" : contentType) + "'. Expected '"
+          + EXPECTED_CONTENT_TYPE + "'.");
+    }
+  }
+
   private RPCServletUtils() {
     // Not instantiable
   }
diff --git a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
index 652c757..e5e9747 100644
--- a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
+++ b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
@@ -27,6 +27,7 @@
 import java.util.Map;
 
 import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -73,7 +74,7 @@
 
       // Read the request fully.
       //
-      String requestPayload = RPCServletUtils.readContentAsUtf8(request);
+      String requestPayload = readContent(request);
 
       // Let subclasses see the serialized request.
       //
@@ -228,7 +229,8 @@
       try {
         if (is != null) {
           try {
-            serializationPolicy = SerializationPolicyLoader.loadFromStream(is, null);
+            serializationPolicy = SerializationPolicyLoader.loadFromStream(is,
+                null);
           } catch (ParseException e) {
             getServletContext().log(
                 "ERROR: Failed to parse the policy file '"
@@ -319,9 +321,24 @@
   }
 
   /**
+   * Override this method in order to control the parsing of the incoming
+   * request. For example, you may want to bypass the check of the Content-Type
+   * and character encoding headers in the request, as some proxies re-write the
+   * request headers.  Note that bypassing these checks may expose the servlet to
+   * some cross-site vulnerabilities.
+   * 
+   * @param request the incoming request
+   * @return the content of the incoming request encoded as a string.
+   */
+  protected String readContent(HttpServletRequest request)
+      throws ServletException, IOException {
+    return RPCServletUtils.readContentAsUtf8(request, true);
+  }
+
+  /**
    * Determines whether the response to a given servlet request should or should
    * not be GZIP compressed. This method is only called in cases where the
-   * requestor accepts GZIP encoding.
+   * requester accepts GZIP encoding.
    * <p>
    * This implementation currently returns <code>true</code> if the response
    * string's estimated byte length is longer than 256 bytes. Subclasses can
diff --git a/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc b/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
index 511681b..eae6bd1 100644
--- a/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
+++ b/user/src/com/google/gwt/user/tools/AppClassTemplate.javasrc
@@ -20,10 +20,14 @@
   public void onModuleLoad() {
     Image img = new Image("http://code.google.com/webtoolkit/logo-185x175.png");
     Button button = new Button("Click me");
-
+    
+    // We can add style names
+    button.addStyleName("pc-template-btn");
+    // or we can set an id on a specific element for styling
+    img.getElement().setId("pc-template-img");
+    
     VerticalPanel vPanel = new VerticalPanel();
-    // We can add style names.
-    vPanel.addStyleName("widePanel");
+    vPanel.setWidth("100%");
     vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
     vPanel.add(img);
     vPanel.add(button);
diff --git a/user/src/com/google/gwt/user/tools/AppCss.csssrc b/user/src/com/google/gwt/user/tools/AppCss.csssrc
index 9c6a381..3cf302f 100644
--- a/user/src/com/google/gwt/user/tools/AppCss.csssrc
+++ b/user/src/com/google/gwt/user/tools/AppCss.csssrc
@@ -1,13 +1,12 @@
 /** Add css rules here for your application. */
-button {
+
+
+/** Example rules used by the template application (remove for your app) */
+.pc-template-btn {
   display: block;
   font-size: 16pt
 }
 
-.widePanel {
-  width: 100%
-}
-
-img {
+#pc-template-img {
   margin-top: 20px;
-}
\ No newline at end of file
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/String.java b/user/super/com/google/gwt/emul/java/lang/String.java
index 7dd5f8c..3c80553 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -667,13 +667,14 @@
         count++;
       }
     }
-    // all blank delimiters at the end are supposed to disappear if maxMatch ==0
+    // all blank delimiters at the end are supposed to disappear if maxMatch == 0
     if (maxMatch == 0) {
-      for (var i = out.length - 1; i >= 0; i--) {
-        if(out[i] != "") {
-          out.splice(i + 1,out.length - (i + 1));
-          break;
-        }
+      var lastNonEmpty = out.length;
+      while (lastNonEmpty > 0 && out[lastNonEmpty - 1] == "") {
+        --lastNonEmpty;
+      }
+      if (lastNonEmpty < out.length) {
+        out.splice(lastNonEmpty, out.length - lastNonEmpty);
       }
     }
     var jr = @java.lang.String::__createArray(I)(out.length);
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index a12e24e..ed22899 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -31,7 +31,12 @@
 
   private static final class ArrayList<E> extends AbstractList<E> implements
       RandomAccess, Serializable {
-    private final E[] array;
+
+    /**
+     * The only reason this is non-final is so that E[] (and E) will be exposed
+     * for serialization.
+     */
+    private E[] array;
 
     ArrayList(E[] array) {
       assert (array != null);
diff --git a/user/super/com/google/gwt/emul/java/util/TreeMap.java b/user/super/com/google/gwt/emul/java/util/TreeMap.java
index fa3cb12..2edb562 100644
--- a/user/super/com/google/gwt/emul/java/util/TreeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/TreeMap.java
@@ -71,13 +71,8 @@
     }
 
     public void remove() {
-      if (last == null) {
-        throw new IllegalStateException("Must call next() before remove().");
-      } else {
-        iter.remove();
-        TreeMap.this.remove(last.getKey());
-        last = null;
-      }
+      iter.remove();
+      TreeMap.this.remove(last.getKey());
     }
 
     private void inOrderAdd(List<Map.Entry<K, V>> list, SubMapType type,
@@ -97,12 +92,12 @@
     }
 
     private boolean inRange(SubMapType type, K key, K fromKey, K toKey) {
-      if (type == SubMapType.Head || type == SubMapType.Range) {
+      if (type.toKeyValid()) {
         if (cmp.compare(key, toKey) >= 0) {
           return false;
         }
       }
-      if (type == SubMapType.Tail || type == SubMapType.Range) {
+      if (type.fromKeyValid()) {
         if (cmp.compare(key, fromKey) < 0) {
           return false;
         }
@@ -337,6 +332,11 @@
         }
 
         @Override
+        public boolean isEmpty() {
+          return SubMap.this.isEmpty();
+        }
+
+        @Override
         public Iterator<Entry<K, V>> iterator() {
           return new EntryIterator(type, fromKey, toKey);
         }
@@ -372,8 +372,8 @@
     }
 
     public K firstKey() {
-      Node<K, V> node = getNodeAtOrAfter(fromKey);
-      if (node == null || cmp.compare(node.key, toKey) > 0) {
+      Node<K, V> node = throwNSE(getFirstSubmapNode());
+      if (type.toKeyValid() && cmp.compare(node.key, toKey) > 0) {
         throw new NoSuchElementException();
       }
       return node.key;
@@ -390,20 +390,25 @@
     }
 
     public SortedMap<K, V> headMap(K toKey) {
-      if (cmp.compare(toKey, this.toKey) > 0) {
+      if (type.toKeyValid() && cmp.compare(toKey, this.toKey) > 0) {
         throw new IllegalArgumentException("subMap: " + toKey
             + " greater than " + this.toKey);
       }
-      if (type == SubMapType.Range || type == SubMapType.Tail) {
+      if (type.fromKeyValid()) {
         return TreeMap.this.subMap(fromKey, toKey);
       } else {
         return TreeMap.this.headMap(toKey);
       }
     }
 
+    @Override
+    public boolean isEmpty() {
+      return getFirstSubmapNode() == null;
+    }
+
     public K lastKey() {
-      Node<K, V> node = getNodeBefore(toKey);
-      if (node == null || cmp.compare(node.key, fromKey) < 0) {
+      Node<K, V> node = throwNSE(getLastSubmapNode());
+      if (type.fromKeyValid() && cmp.compare(node.key, fromKey) < 0) {
         throw new NoSuchElementException();
       }
       return node.key;
@@ -429,13 +434,11 @@
     }
 
     public SortedMap<K, V> subMap(K newFromKey, K newToKey) {
-      if ((type == SubMapType.Range || type == SubMapType.Tail)
-          && cmp.compare(newFromKey, fromKey) < 0) {
+      if (type.fromKeyValid() && cmp.compare(newFromKey, fromKey) < 0) {
         throw new IllegalArgumentException("subMap: " + newFromKey
             + " less than " + fromKey);
       }
-      if ((type == SubMapType.Range || type == SubMapType.Head)
-          && cmp.compare(newToKey, toKey) > 0) {
+      if (type.toKeyValid() && cmp.compare(newToKey, toKey) > 0) {
         throw new IllegalArgumentException("subMap: " + newToKey
             + " greater than " + toKey);
       }
@@ -443,25 +446,44 @@
     }
 
     public SortedMap<K, V> tailMap(K fromKey) {
-      if ((type == SubMapType.Range || type == SubMapType.Tail)
-          && cmp.compare(fromKey, this.fromKey) < 0) {
+      if (type.fromKeyValid() && cmp.compare(fromKey, this.fromKey) < 0) {
         throw new IllegalArgumentException("subMap: " + fromKey + " less than "
             + this.fromKey);
       }
-      if (type == SubMapType.Range || type == SubMapType.Head) {
+      if (type.toKeyValid()) {
         return TreeMap.this.subMap(fromKey, toKey);
       } else {
         return TreeMap.this.tailMap(fromKey);
       }
     }
 
+    private Node<K, V> getFirstSubmapNode() {
+      Node<K, V> node;
+      if (type.fromKeyValid()) {
+        node = getNodeAtOrAfter(fromKey);
+      } else {
+        node = getFirstNode();
+      }
+      return node;
+    }
+
+    private Node<K, V> getLastSubmapNode() {
+      Node<K, V> node;
+      if (type.toKeyValid()) {
+        node = getNodeBefore(toKey);
+      } else {
+        node = getLastNode();
+      }
+      return node;
+    }
+
     private boolean inRange(K key) {
-      if (type == SubMapType.Head || type == SubMapType.Range) {
+      if (type.toKeyValid()) {
         if (cmp.compare(key, toKey) >= 0) {
           return false;
         }
       }
-      if (type == SubMapType.Tail || type == SubMapType.Range) {
+      if (type.fromKeyValid()) {
         if (cmp.compare(key, fromKey) < 0) {
           return false;
         }
@@ -471,7 +493,47 @@
   }
 
   private enum SubMapType {
-    All, Head, Range, Tail,
+    All,
+    
+    Head {
+      @Override
+      public boolean toKeyValid() {
+        return true;
+      }
+    },
+    
+    Range {
+      @Override
+      public boolean fromKeyValid() {
+        return true;
+      }
+
+      @Override
+      public boolean toKeyValid() {
+        return true;
+      }
+    },
+    
+    Tail {
+      @Override
+      public boolean fromKeyValid() {
+        return true;
+      }
+    };
+    
+    /**
+     * @return true if this submap type uses a from-key.
+     */
+    public boolean fromKeyValid() {
+      return false;
+    }
+    
+    /**
+     * @return true if this submap type uses a to-key.
+     */
+    public boolean toKeyValid() {
+      return false;
+    }
   }
 
   /**
@@ -497,6 +559,24 @@
     return 1 - child;
   }
 
+  /**
+   * Throw a NoSuchElementException if the specified node is null.
+   * 
+   * Used to clean up error checking at use sites.
+   * 
+   * @param node node to check
+   * @param <NK> key type
+   * @param <NV> value type
+   * @return node, guaranteed to be non-null
+   * @throws NoSuchElementException if node is null
+   */
+  private static <NK, NV> Node<NK, NV> throwNSE(Node<NK, NV> node) {
+    if (node == null) {
+      throw new NoSuchElementException();
+    }
+    return node;
+  }
+
   // The comparator to use.
   private Comparator<? super K> cmp;
 
@@ -555,14 +635,7 @@
   }
 
   public K firstKey() {
-    if (root == null) {
-      throw new NoSuchElementException();
-    }
-    Node<K, V> node = root;
-    while (node.child[LEFT] != null) {
-      node = node.child[LEFT];
-    }
-    return node.key;
+    return throwNSE(getFirstNode()).key;
   }
 
   @SuppressWarnings("unchecked")
@@ -584,14 +657,7 @@
   }
 
   public K lastKey() {
-    if (root == null) {
-      throw new NoSuchElementException();
-    }
-    Node<K, V> node = root;
-    while (node.child[RIGHT] != null) {
-      node = node.child[RIGHT];
-    }
-    return node.key;
+    return throwNSE(getLastNode()).key;
   }
 
   @Override
@@ -633,66 +699,44 @@
    * key.
    * 
    * @param key the key to search for
-   * @return the next node, or null if there is none.
+   * @return the next node, or null if there is none
    */
   protected Node<K, V> getNodeAtOrAfter(K key) {
-    if (root == null) {
-      return null;
-    }
     Node<K, V> foundNode = null;
     Node<K, V> node = root;
-    while (true) {
+    while (node != null) {
       int c = cmp.compare(key, node.key);
       if (c == 0) {
         return node;
       } else if (c > 0) {
         node = node.child[RIGHT];
-        if (node == null) {
-          // ran off the tree and we are past this node, so return best one
-          return foundNode;
-        }
       } else {
         foundNode = node;
-        Node<K, V> nextNode = node.child[LEFT];
-        if (nextNode == null) {
-          // ran off the tree and we are before this node, so return it
-          return node;
-        }
-        node = nextNode;
+        node = node.child[LEFT];
       }
     }
+    return foundNode;
   }
 
   /**
    * Return the last node which is strictly less than the given key.
    * 
    * @param key the key to search for
-   * @return the previous node, or null if there is none.
+   * @return the previous node, or null if there is none
    */
   protected Node<K, V> getNodeBefore(K key) {
-    if (root == null) {
-      return null;
-    }
     Node<K, V> foundNode = null;
     Node<K, V> node = root;
-    while (true) {
+    while (node != null) {
       int c = cmp.compare(key, node.key);
       if (c <= 0) {
         node = node.child[LEFT];
-        if (node == null) {
-          // ran off the tree and we are past this node, so return best one
-          return foundNode;
-        }
       } else {
         foundNode = node;
-        Node<K, V> nextNode = node.child[RIGHT];
-        if (nextNode == null) {
-          // ran off the tree and we are before this node, so return it
-          return node;
-        }
-        node = nextNode;
+        node = node.child[RIGHT];
       }
     }
+    return foundNode;
   }
 
   /**
@@ -712,7 +756,7 @@
   }
 
   /**
-   * Internal helper function for public (@see assertCorrectness()).
+   * Internal helper function for public {@link #assertCorrectness()}.
    * 
    * @param tree the subtree to validate.
    * @param isRed true if the parent of this node is red.
@@ -768,6 +812,47 @@
     return null;
   }
 
+  /**
+   * @return the left-most node of the tree, or null if empty
+   */
+  private Node<K, V> getFirstNode() {
+    if (root == null) {
+      return null;
+    }
+    Node<K, V> node = root;
+    while (node.child[LEFT] != null) {
+      node = node.child[LEFT];
+    }
+    return node;
+  }
+
+  /**
+   * @return the right-most node of the tree, or null if empty
+   */
+  private Node<K, V> getLastNode() {
+    if (root == null) {
+      return null;
+    }
+    Node<K, V> node = root;
+    while (node.child[RIGHT] != null) {
+      node = node.child[RIGHT];
+    }
+    return node;
+  }
+
+  /**
+   * Insert a node into a subtree, collecting state about the insertion.
+   * 
+   * If the same key already exists, the value of the node is overwritten
+   * with the value from the new node instead.
+   * 
+   * @param tree subtree to insert into
+   * @param newNode new node to insert
+   * @param state result of the insertion:
+   *     state.found true if the key already existed in the tree
+   *     state.value the old value if the key existed 
+   * @return the new subtree root
+   */
   private Node<K, V> insert(Node<K, V> tree, Node<K, V> newNode, State<V> state) {
     if (tree == null) {
       return newNode;
@@ -779,7 +864,7 @@
         tree.value = newNode.value;
         return tree;
       }
-      int childNum = (c > 0) ? 0 : 1;
+      int childNum = (c > 0) ? LEFT : RIGHT;
       tree.child[childNum] = insert(tree.child[childNum], newNode, state);
       if (isRed(tree.child[childNum])) {
         if (isRed(tree.child[otherChild(childNum)])) {
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index 7eb613b..4c744e7 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -615,6 +615,23 @@
       }
       fail("should not be reached");
     }
+
+    /*
+     * Issue 2770: labeled breaks in a switch statement with no default case
+     * should not be pruned.
+     */
+    outer : while (true) {
+      switch (THREE) {
+        case 0:
+        case 1:
+        case 2:
+        case 3:
+          break outer;
+        case 4:
+        case 5:
+          break;
+      }
+    }
   }
 
   public void testLocalClasses() {
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
index 8ba7541..a28f341 100644
--- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -54,18 +54,6 @@
     }
   }
 
-  private static class TestGenericList extends AbstractList<Object> {
-    @Override
-    public Object get(int index) {
-      return this;
-    }
-
-    @Override
-    public int size() {
-      return 42;
-    }
-  }
-
   private static class TestCovariantChild extends TestCovariantSuper {
     @Override
     public native String foo(String val) /*-{
@@ -96,6 +84,18 @@
     }-*/;
   }
 
+  private static class TestGenericList extends AbstractList<Object> {
+    @Override
+    public Object get(int index) {
+      return this;
+    }
+
+    @Override
+    public int size() {
+      return 42;
+    }
+  }
+
   static String sFoo(String s) {
     return s + "foo";
   }
diff --git a/user/test/com/google/gwt/dev/jjs/test/JsniConstructorTest.java b/user/test/com/google/gwt/dev/jjs/test/JsniConstructorTest.java
index 29d0f2f..657b2ae 100644
--- a/user/test/com/google/gwt/dev/jjs/test/JsniConstructorTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/JsniConstructorTest.java
@@ -28,6 +28,49 @@
  */
 public class JsniConstructorTest extends GWTTestCase {
 
+  private interface A1 {
+    void a1();
+  }
+
+  private interface A2 extends A1 {
+    void a2();
+  }
+
+  private interface A3 {
+    void a3();
+  }
+
+  private static abstract class C1 implements A2 {
+    static void s1() {
+    }
+
+    public abstract void c1();
+  }
+
+  private static class C2 extends C1 implements A3 {
+    static void s2() {
+    }
+
+    public void a1() {
+    }
+
+    public void a2() {
+    }
+
+    public void a3() {
+    }
+
+    public void c1() {
+    }
+
+    public void c2() {
+    }
+
+    public String toString() {
+      return null;
+    }
+  }
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -45,7 +88,7 @@
     } catch (Throwable t) {
       fail("Expecting a StaticObjectException, got a " + t.getClass().getName());
     }
-    
+
     try {
       staticArg(true);
       fail("Should have thrown a runtime exception");
@@ -55,7 +98,35 @@
       fail("Expecting a RuntimeException, got a " + t.getClass().getName());
     }
   }
-  
+
+  public native void testInheritedMethodRef() /*-{
+    @com.google.gwt.dev.jjs.test.JsniConstructorTest.C1::s1()();
+    @com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::s1()();
+    @com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::s2()();
+
+    var o = @com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::new()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.A1::a1()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.A2::a1()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C1::a1()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::a1()();
+
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.A2::a2()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C1::a2()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::a2()();
+
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.A3::a3()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::a3()();
+
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C1::c1()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::c1()();
+
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::c2()();
+
+    o.@java.lang.Object::toString()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C1::toString()();
+    o.@com.google.gwt.dev.jjs.test.JsniConstructorTest.C2::toString()();
+  }-*/;
+
   public void testJsniConstructors() {
     StaticObject o = staticArg(1);
     assertEquals(1, o.foo());
@@ -83,43 +154,45 @@
   }
 
   private native InstanceObject instanceArg(StaticObject obj, int i) /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject;I)(obj,i);
+    return @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject;I)(obj,i);
   }-*/;
 
-  private native NestedInstanceObject nestedInstanceArg(InstanceObject obj, int i) /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject.NestedInstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject$InstanceObject;I)(obj,i);
+  private native NestedInstanceObject nestedInstanceArg(InstanceObject obj,
+      int i) /*-{
+    return @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject.NestedInstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject$InstanceObject;I)(obj,i);
   }-*/;
 
   private native NoArgObject noArg() /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject.NoArgObject::new()();
+    return @com.google.gwt.dev.jjs.test.StaticObject.NoArgObject::new()();
   }-*/;
 
   private native NoInitObject noInit() /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject.NoInitObject::new()();
+    return @com.google.gwt.dev.jjs.test.StaticObject.NoInitObject::new()();
   }-*/;
 
   private native InstanceObject passAndReturnInstance(StaticObject obj, int i) /*-{
-  var f = @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject;I);
-  return f.call(null, obj, i);
+    var f = @com.google.gwt.dev.jjs.test.StaticObject.InstanceObject::new(Lcom/google/gwt/dev/jjs/test/StaticObject;I);
+    return f.call(null, obj, i);
   }-*/;
 
   private native StaticObject passAndReturnStatic(int i) /*-{
-  var f = @com.google.gwt.dev.jjs.test.StaticObject::new(I);
-  return f(i);
+    var f = @com.google.gwt.dev.jjs.test.StaticObject::new(I);
+    return f(i);
   }-*/;
 
   /**
    * Calls a constructor that always throws an exception.
    */
-  private native StaticObject staticArg(boolean throwRuntime) throws StaticObjectException /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject::new(Z)(throwRuntime);
+  private native StaticObject staticArg(boolean throwRuntime)
+      throws StaticObjectException /*-{
+    return @com.google.gwt.dev.jjs.test.StaticObject::new(Z)(throwRuntime);
   }-*/;
-  
+
   private native StaticObject staticArg(int i) /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject::new(I)(i);
+    return @com.google.gwt.dev.jjs.test.StaticObject::new(I)(i);
   }-*/;
 
   private native StaticInnerObject staticInnerArg(int i) /*-{
-  return @com.google.gwt.dev.jjs.test.StaticObject.StaticInnerObject::new(I)(i);
+    return @com.google.gwt.dev.jjs.test.StaticObject.StaticInnerObject::new(I)(i);
   }-*/;
 }
diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java
index 9fb4657..0471fb5 100644
--- a/user/test/com/google/gwt/dom/client/ElementTest.java
+++ b/user/test/com/google/gwt/dom/client/ElementTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dom.client;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DeferredCommand;
@@ -304,4 +305,27 @@
     assertEquals("foo", nodes.getItem(0).getInnerText());
     assertEquals("bar", nodes.getItem(1).getInnerText());
   }
+
+  /**
+   * Tests HeadingElement.as() (it has slightly more complex assertion logic
+   * than most).
+   */
+  public void testHeadingElementAs() {
+    DivElement placeHolder = Document.get().createDivElement();
+
+    for (int i = 0; i < 6; ++i) {
+      placeHolder.setInnerHTML("<H" + (i + 1) + "/>");
+      assertNotNull(HeadingElement.as(placeHolder.getFirstChildElement()));
+    }
+
+    if (!GWT.isScript()) {
+      Element notHeading = Document.get().createDivElement();
+      try {
+        HeadingElement.as(notHeading);
+        fail("Expected assertion failure");
+      } catch (AssertionError e) {
+        // this *should* happen.
+      }
+    }
+  }
 }
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringTest.java b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
index 0041edd..20c1a77 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
@@ -393,24 +393,25 @@
 
   public void testSplit() {
     compareList("fullSplit", new String[] {"abc", "", "", "de", "f"},
-        "abcxxxdexfxx".split("x"));
+        hideFromCompiler("abcxxxdexfxx").split("x"));
     compareList("emptyRegexSplit", new String[] {
         "", "a", "b", "c", "x", "x", "d", "e", "x", "f", "x"},
-        "abcxxdexfx".split(""));
-    compareList("2:", "boo:and:foo".split(":", 2), new String[] {
-        "boo", "and:foo"});
-    compareList("5:", "boo:and:foo".split(":", 5), new String[] {
-        "boo", "and", "foo"});
-    compareList("-2:", "boo:and:foo".split(":", -2), new String[] {
-        "boo", "and", "foo"});
-    compareList("5o", "boo:and:foo".split("o", 5), new String[] {
-        "b", "", ":and:f", "", ""});
-    compareList("-2o", "boo:and:foo".split("o", -2), new String[] {
-        "b", "", ":and:f", "", ""});
-    compareList("0o", "boo:and:foo".split("o", 0), new String[] {
-        "b", "", ":and:f"});
-    compareList("0:", "boo:and:foo".split(":", 0), new String[] {
-        "boo", "and", "foo"});
+        hideFromCompiler("abcxxdexfx").split(""));
+    String booAndFoo = hideFromCompiler("boo:and:foo");
+    compareList("2:", new String[] {"boo", "and:foo"}, booAndFoo.split(":", 2));
+    compareList("5:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":",
+        5));
+    compareList("-2:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":",
+        -2));
+    compareList("5o", new String[] {"b", "", ":and:f", "", ""},
+        booAndFoo.split("o", 5));
+    compareList("-2o", new String[] {"b", "", ":and:f", "", ""},
+        booAndFoo.split("o", -2));
+    compareList("0o", new String[] {"b", "", ":and:f"}, booAndFoo.split("o", 0));
+    compareList("0:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":",
+        0));
+    // issue 2742
+    compareList("issue2742", new String[] {}, hideFromCompiler("/").split("/", 0));
   }
 
   public void testStartsWith() {
diff --git a/user/test/com/google/gwt/emultest/java/util/TreeMapStringStringTest.java b/user/test/com/google/gwt/emultest/java/util/TreeMapStringStringTest.java
index 55a49fc..8f7f714 100644
--- a/user/test/com/google/gwt/emultest/java/util/TreeMapStringStringTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/TreeMapStringStringTest.java
@@ -15,11 +15,119 @@
  */
 package com.google.gwt.emultest.java.util;
 
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+
 /**
  * Tests <code>TreeMap</code> with Strings and the natural comparator.
  */
 public class TreeMapStringStringTest extends TreeMapTest<String, String> {
 
+  public void testHeadMapEqualsFirst() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap = sortedMap.headMap("aa");
+    assertEquals("length", 0, subMap.size());
+    Set<String> kset = subMap.keySet();
+    Iterator<String> it = kset.iterator();
+    assertFalse("iterator[0]", it.hasNext());
+  }
+
+  public void testHeadMapEqualsSecond() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap = sortedMap.headMap("bb");
+    assertEquals("length", 1, subMap.size());
+    Set<String> kset = subMap.keySet();
+    Iterator<String> it = kset.iterator();
+    assertTrue("iterator[0]", it.hasNext());
+    assertEquals("iterator[0]", "aa", it.next());
+    assertFalse("iterator[1]", it.hasNext());
+    assertEquals("firstKey", "aa", subMap.firstKey());
+    assertEquals("lastKey", "aa", subMap.lastKey());
+  }
+
+  /**
+   * Perform some tests on submap that are hard to do without specific knowledge
+   * of the keys used.
+   */
+  public void testHeadMapSimple() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap = sortedMap.headMap("bz");
+    assertEquals("length", 2, subMap.size());
+    Set<String> kset = subMap.keySet();
+    Iterator<String> it = kset.iterator();
+    assertTrue("iterator[0]", it.hasNext());
+    assertEquals("iterator[0]", "aa", it.next());
+    assertTrue("iterator[1]", it.hasNext());
+    assertEquals("iterator[1]", "bb", it.next());
+    assertFalse("iterator[2]", it.hasNext());
+    // issue 2638
+    assertEquals("firstKey", "aa", subMap.firstKey());
+    assertEquals("lastKey", "bb", subMap.lastKey());
+  }
+
+  /**
+   * Tests that compositing submap operations function as expected.
+   */
+  public void testSubMapComposite() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap1 = sortedMap.headMap("cz").tailMap("bb");
+    SortedMap<String, String> subMap2 = sortedMap.tailMap("bb").headMap("cz");
+    SortedMap<String, String> subMap3 = sortedMap.subMap("bb", "cz");
+    assertEquals("headMap(tailMap) should equal tailMap(headMap)", subMap1,
+        subMap2);
+    assertEquals("headMap(tailMap) should equal subMap", subMap1, subMap3);
+    assertEquals("headMap(tailMap) size", 2, subMap1.size());
+  }
+
+  public void testTailMapPastEnd() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap = sortedMap.tailMap("dz");
+    assertEquals("length", 0, subMap.size());
+    Set<String> kset = subMap.keySet();
+    Iterator<String> it = kset.iterator();
+    assertFalse("iterator[0]", it.hasNext());
+    try {
+      subMap.firstKey();
+      fail("firstKey should have thrown NoSuchElementException");
+    } catch (NoSuchElementException expected) {
+    }
+    try {
+      subMap.lastKey();
+      fail("lastKey should have thrown NoSuchElementException");
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  public void testTailMapSimple() {
+    SortedMap<String, String> sortedMap = createKnownKeysMap();
+    SortedMap<String, String> subMap = sortedMap.tailMap("bb");
+    assertEquals("length", 3, subMap.size());
+    Set<String> kset = subMap.keySet();
+    Iterator<String> it = kset.iterator();
+    assertTrue("iterator[0]", it.hasNext());
+    assertEquals("iterator[0]", "bb", it.next());
+    assertTrue("iterator[1]", it.hasNext());
+    assertEquals("iterator[1]", "cc", it.next());
+    assertTrue("iterator[2]", it.hasNext());
+    assertEquals("iterator[2]", "dd", it.next());
+    assertFalse("iterator[3]", it.hasNext());
+    // issue 2638
+    assertEquals("firstKey", "bb", subMap.firstKey());
+    assertEquals("lastKey", "dd", subMap.lastKey());
+  }
+
+  @Override
+  protected Object getConflictingKey() {
+    return new Integer(1);
+  }
+
+  @Override
+  protected Object getConflictingValue() {
+    return new Long(42);
+  }
+
   @Override
   String getGreaterThanMaximumKey() {
     return "z";
@@ -30,12 +138,6 @@
     return convertToStringArray(getSampleKeys());
   }
 
-  private String[] convertToStringArray(Object[] objArray) {
-    String[] strArray = new String[objArray.length];
-    System.arraycopy(objArray, 0, strArray, 0, objArray.length);
-    return strArray;
-  }
-
   @Override
   String[] getKeys2() {
     return convertToStringArray(getOtherKeys());
@@ -56,13 +158,18 @@
     return convertToStringArray(getOtherValues());
   }
 
-  @Override
-  protected Object getConflictingKey() {
-    return new Integer(1);
+  private String[] convertToStringArray(Object[] objArray) {
+    String[] strArray = new String[objArray.length];
+    System.arraycopy(objArray, 0, strArray, 0, objArray.length);
+    return strArray;
   }
 
-  @Override
-  protected Object getConflictingValue() {
-    return new Long(42);
+  private SortedMap<String, String> createKnownKeysMap() {
+    SortedMap<String, String> sortedMap = createSortedMap();
+    sortedMap.put("dd", "dval");
+    sortedMap.put("aa", "aval");
+    sortedMap.put("cc", "cval");
+    sortedMap.put("bb", "bval");
+    return sortedMap;
   }
 }
diff --git a/user/test/com/google/gwt/user/RPCSuite.java b/user/test/com/google/gwt/user/RPCSuite.java
index 79e1b93..24d44ec 100644
--- a/user/test/com/google/gwt/user/RPCSuite.java
+++ b/user/test/com/google/gwt/user/RPCSuite.java
@@ -26,6 +26,7 @@
 import com.google.gwt.user.client.rpc.ValueTypesTest;
 import com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilderTest;
 import com.google.gwt.user.rebind.rpc.TypeHierarchyUtilsTest;
+import com.google.gwt.user.server.rpc.RPCServletUtilsTest;
 import com.google.gwt.user.server.rpc.RPCTest;
 import com.google.gwt.user.server.rpc.SerializationPolicyLoaderTest;
 import com.google.gwt.user.server.rpc.impl.LegacySerializationPolicyTest;
@@ -66,7 +67,7 @@
     suite.addTestSuite(LegacySerializationPolicyTest.class);
     suite.addTestSuite(StandardSerializationPolicyTest.class);
     suite.addTestSuite(SerializationPolicyLoaderTest.class);
-
+    suite.addTestSuite(RPCServletUtilsTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
index b35e439..78eac3f 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -17,6 +17,12 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArrayList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArraysAsList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
 
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -29,7 +35,7 @@
 import java.util.Vector;
 
 /**
- * TODO: document me.
+ * Tests collections across RPC.
  */
 public class CollectionsTest extends GWTTestCase {
   /**
@@ -40,19 +46,22 @@
 
   private CollectionsTestServiceAsync collectionsTestService;
 
-  public void _testDateArray() {
+  /**
+   * TODO: Why is this disabled???
+   */
+  public void disabledTestDateArray() {
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Date[] expected = TestSetFactory.createDateArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Date[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Date[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Date[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -68,14 +77,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final int[] expected = TestSetFactory.createVeryLargeArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<int[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(int[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (int[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -89,36 +98,38 @@
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
-    service.echo(TestSetFactory.createArrayList(), new AsyncCallback() {
-      public void onFailure(Throwable caught) {
-        TestSetValidator.rethrowException(caught);
-      }
+    service.echo(TestSetFactory.createArrayList(),
+        new AsyncCallback<ArrayList<MarkerTypeArrayList>>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
 
-      public void onSuccess(Object result) {
-        assertNotNull(result);
-        assertTrue(TestSetValidator.isValid((ArrayList) result));
-        finishTest();
-      }
-    });
+          public void onSuccess(ArrayList<MarkerTypeArrayList> result) {
+            assertNotNull(result);
+            assertTrue(TestSetValidator.isValid(result));
+            finishTest();
+          }
+        });
   }
 
   public void testArraysAsList() {
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
-    final List expected = TestSetFactory.createArraysAsList();
+    final List<MarkerTypeArraysAsList> expected = TestSetFactory.createArraysAsList();
 
-    service.echoArraysAsList(expected, new AsyncCallback() {
-      public void onFailure(Throwable caught) {
-        TestSetValidator.rethrowException(caught);
-      }
+    service.echoArraysAsList(expected,
+        new AsyncCallback<List<MarkerTypeArraysAsList>>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
 
-      public void onSuccess(Object result) {
-        assertNotNull(result);
-        assertEquals(expected, result);
-        finishTest();
-      }
-    });
+          public void onSuccess(List<MarkerTypeArraysAsList> result) {
+            assertNotNull(result);
+            assertEquals(expected, result);
+            finishTest();
+          }
+        });
   }
 
   public void testBooleanArray() {
@@ -126,14 +137,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Boolean[] expected = TestSetFactory.createBooleanArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Boolean[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Boolean[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Boolean[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -144,14 +155,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Byte[] expected = TestSetFactory.createByteArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Byte[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Byte[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Byte[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -162,14 +173,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Character[] expected = TestSetFactory.createCharArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Character[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Character[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Character[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -180,14 +191,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Double[] expected = TestSetFactory.createDoubleArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Double[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Double[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -198,14 +209,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Float[] expected = TestSetFactory.createFloatArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Float[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Float[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -215,33 +226,34 @@
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
-    final HashMap expected = TestSetFactory.createHashMap();
-    service.echo(expected, new AsyncCallback() {
-      public void onFailure(Throwable caught) {
-        TestSetValidator.rethrowException(caught);
-      }
+    final HashMap<String, MarkerTypeHashMap> expected = TestSetFactory.createHashMap();
+    service.echo(expected,
+        new AsyncCallback<HashMap<String, MarkerTypeHashMap>>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
 
-      public void onSuccess(Object result) {
-        assertNotNull(result);
-        assertTrue(TestSetValidator.isValid(expected, (HashMap) result));
-        finishTest();
-      }
-    });
+          public void onSuccess(HashMap<String, MarkerTypeHashMap> result) {
+            assertNotNull(result);
+            assertTrue(TestSetValidator.isValid(expected, result));
+            finishTest();
+          }
+        });
   }
 
   public void testHashSet() {
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
-    final HashSet expected = TestSetFactory.createHashSet();
-    service.echo(expected, new AsyncCallback() {
+    final HashSet<MarkerTypeHashSet> expected = TestSetFactory.createHashSet();
+    service.echo(expected, new AsyncCallback<HashSet<MarkerTypeHashSet>>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(HashSet<MarkerTypeHashSet> result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.isValid(expected, (HashSet) result));
+        assertTrue(TestSetValidator.isValid(expected, result));
         finishTest();
       }
     });
@@ -252,14 +264,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Integer[] expected = TestSetFactory.createIntegerArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Integer[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Integer[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Integer[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -269,20 +281,20 @@
     delayTestFinish(TEST_DELAY);
     CollectionsTestServiceAsync service = getServiceAsync();
 
-    final LinkedHashMap<String, IsSerializable> expected = TestSetFactory.createLinkedHashMap();
+    final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLinkedHashMap();
 
     service.echo(expected,
-        new AsyncCallback<LinkedHashMap<String, IsSerializable>>() {
+        new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(LinkedHashMap<String, IsSerializable> result) {
+          public void onSuccess(
+              LinkedHashMap<String, MarkerTypeLinkedHashMap> result) {
             assertNotNull(result);
             expected.get("SerializableSet");
             result.get("SerializableSet");
-            assertTrue(TestSetValidator.isValid(expected,
-                (LinkedHashMap) result));
+            assertTrue(TestSetValidator.isValid(expected, result));
             finishTest();
           }
         });
@@ -292,15 +304,16 @@
     delayTestFinish(TEST_DELAY);
     CollectionsTestServiceAsync service = getServiceAsync();
 
-    final LinkedHashMap<String, IsSerializable> expected = TestSetFactory.createLRULinkedHashMap();
+    final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLRULinkedHashMap();
 
     service.echo(expected,
-        new AsyncCallback<LinkedHashMap<String, IsSerializable>>() {
+        new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(LinkedHashMap actual) {
+          public void onSuccess(
+              LinkedHashMap<String, MarkerTypeLinkedHashMap> actual) {
             assertNotNull(actual);
             expected.get("SerializableSet");
             actual.get("SerializableSet");
@@ -315,14 +328,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Long[] expected = TestSetFactory.createLongArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Long[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Long[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Long[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -333,13 +346,13 @@
 
     final boolean[] expected = TestSetFactory.createPrimitiveBooleanArray();
     CollectionsTestServiceAsync service = getServiceAsync();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<boolean[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
-        assertTrue(TestSetValidator.equals(expected, (boolean[]) result));
+      public void onSuccess(boolean[] result) {
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -350,13 +363,13 @@
 
     final byte[] expected = TestSetFactory.createPrimitiveByteArray();
     CollectionsTestServiceAsync service = getServiceAsync();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<byte[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
-        assertTrue(TestSetValidator.equals(expected, (byte[]) result));
+      public void onSuccess(byte[] result) {
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -367,14 +380,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final char[] expected = TestSetFactory.createPrimitiveCharArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<char[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(char[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (char[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -385,14 +398,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final double[] expected = TestSetFactory.createPrimitiveDoubleArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<double[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(double[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (double[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -403,14 +416,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final float[] expected = TestSetFactory.createPrimitiveFloatArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<float[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(float[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (float[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -421,14 +434,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final int[] expected = TestSetFactory.createPrimitiveIntegerArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<int[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(int[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (int[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -439,14 +452,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final long[] expected = TestSetFactory.createPrimitiveLongArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<long[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(long[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (long[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -457,14 +470,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final short[] expected = TestSetFactory.createPrimitiveShortArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<short[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(short[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (short[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -475,14 +488,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final Short[] expected = TestSetFactory.createShortArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<Short[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Short[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (Short[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -547,14 +560,14 @@
 
     CollectionsTestServiceAsync service = getServiceAsync();
     final String[] expected = TestSetFactory.createStringArray();
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<String[]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(String[] result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.equals(expected, (String[]) result));
+        assertTrue(TestSetValidator.equals(expected, result));
         finishTest();
       }
     });
@@ -566,12 +579,12 @@
     CollectionsTestServiceAsync service = getServiceAsync();
     final String[][] expected = new String[][] {
         new String[] {"hello"}, new String[] {"bye"}};
-    service.echo(expected, new AsyncCallback() {
+    service.echo(expected, new AsyncCallback<String[][]>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(String[][] result) {
         assertNotNull(result);
         finishTest();
       }
@@ -582,15 +595,15 @@
     delayTestFinish(TEST_DELAY);
 
     CollectionsTestServiceAsync service = getServiceAsync();
-    final Vector expected = TestSetFactory.createVector();
-    service.echo(expected, new AsyncCallback() {
+    final Vector<MarkerTypeVector> expected = TestSetFactory.createVector();
+    service.echo(expected, new AsyncCallback<Vector<MarkerTypeVector>>() {
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Vector<MarkerTypeVector> result) {
         assertNotNull(result);
-        assertTrue(TestSetValidator.isValid(expected, (Vector) result));
+        assertTrue(TestSetValidator.isValid(expected, result));
         finishTest();
       }
     });
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
index 84c6330..38590f9 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -15,6 +15,14 @@
  */
 package com.google.gwt.user.client.rpc;
 
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArrayList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArraysAsList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
+
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.util.ArrayList;
@@ -22,6 +30,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Vector;
 
@@ -33,7 +42,7 @@
   /**
    * TODO: document me.
    */
-  public static class CollectionsTestServiceException extends Exception {
+  final class CollectionsTestServiceException extends Exception {
     public CollectionsTestServiceException() {
     }
 
@@ -41,8 +50,7 @@
       super(msg);
     }
   }
-
-  ArrayList<IsSerializable> echo(ArrayList<IsSerializable> value)
+  ArrayList<MarkerTypeArrayList> echo(ArrayList<MarkerTypeArrayList> value)
       throws CollectionsTestServiceException;
 
   boolean[] echo(boolean[] value) throws CollectionsTestServiceException;
@@ -59,9 +67,6 @@
 
   Date[] echo(Date[] date) throws CollectionsTestServiceException;
 
-  java.sql.Date[] echo(java.sql.Date[] value)
-      throws CollectionsTestServiceException;
-
   double[] echo(double[] value) throws CollectionsTestServiceException;
 
   Double[] echo(Double[] value) throws CollectionsTestServiceException;
@@ -70,20 +75,28 @@
 
   Float[] echo(Float[] value) throws CollectionsTestServiceException;
 
-  HashMap<String, IsSerializable> echo(HashMap<String, IsSerializable> value)
+  HashMap<String, MarkerTypeHashMap> echo(
+      HashMap<String, MarkerTypeHashMap> value)
       throws CollectionsTestServiceException;
 
-  LinkedHashMap<String, IsSerializable> echo(
-      LinkedHashMap<String, IsSerializable> value)
-      throws CollectionsTestServiceException;
-
-  HashSet<IsSerializable> echo(HashSet<IsSerializable> value)
+  HashSet<MarkerTypeHashSet> echo(HashSet<MarkerTypeHashSet> value)
       throws CollectionsTestServiceException;
 
   int[] echo(int[] value) throws CollectionsTestServiceException;
 
   Integer[] echo(Integer[] value) throws CollectionsTestServiceException;
 
+  java.sql.Date[] echo(java.sql.Date[] value)
+      throws CollectionsTestServiceException;
+
+  LinkedHashMap<String, MarkerTypeLinkedHashMap> echo(
+      LinkedHashMap<String, MarkerTypeLinkedHashMap> value)
+      throws CollectionsTestServiceException;
+
+  LinkedHashSet<MarkerTypeLinkedHashSet> echo(
+      LinkedHashSet<MarkerTypeLinkedHashSet> value)
+      throws CollectionsTestServiceException;
+
   long[] echo(long[] value) throws CollectionsTestServiceException;
 
   Long[] echo(Long[] value) throws CollectionsTestServiceException;
@@ -100,9 +113,10 @@
 
   Timestamp[] echo(Timestamp[] value) throws CollectionsTestServiceException;
 
-  Vector<IsSerializable> echo(Vector<IsSerializable> value)
+  Vector<MarkerTypeVector> echo(Vector<MarkerTypeVector> value)
       throws CollectionsTestServiceException;
 
-  List<IsSerializable> echoArraysAsList(List<IsSerializable> value)
+  List<MarkerTypeArraysAsList> echoArraysAsList(
+      List<MarkerTypeArraysAsList> value)
       throws CollectionsTestServiceException;
 }
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
index 4c9187e..5423060 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -15,6 +15,14 @@
  */
 package com.google.gwt.user.client.rpc;
 
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArrayList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArraysAsList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
+
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.util.ArrayList;
@@ -22,6 +30,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Vector;
 
@@ -29,8 +38,8 @@
  * TODO: document me.
  */
 public interface CollectionsTestServiceAsync {
-  void echo(ArrayList<IsSerializable> value,
-      AsyncCallback<ArrayList<IsSerializable>> callback);
+  void echo(ArrayList<MarkerTypeArrayList> value,
+      AsyncCallback<ArrayList<MarkerTypeArrayList>> callback);
 
   void echo(boolean[] value, AsyncCallback<boolean[]> callback);
 
@@ -46,8 +55,6 @@
 
   void echo(Date[] date, AsyncCallback<Date[]> callback);
 
-  void echo(java.sql.Date[] value, AsyncCallback<java.sql.Date[]> callback);
-
   void echo(double[] value, AsyncCallback<double[]> callback);
 
   void echo(Double[] value, AsyncCallback<Double[]> callback);
@@ -56,19 +63,24 @@
 
   void echo(Float[] value, AsyncCallback<Float[]> callback);
 
-  void echo(HashMap<String, IsSerializable> value,
-      AsyncCallback<HashMap<String, IsSerializable>> callback);
+  void echo(HashMap<String, MarkerTypeHashMap> value,
+      AsyncCallback<HashMap<String, MarkerTypeHashMap>> callback);
 
-  void echo(LinkedHashMap<String, IsSerializable> value,
-      AsyncCallback<LinkedHashMap<String, IsSerializable>> callback);
-
-  void echo(HashSet<IsSerializable> value,
-      AsyncCallback<HashSet<IsSerializable>> callback);
+  void echo(HashSet<MarkerTypeHashSet> value,
+      AsyncCallback<HashSet<MarkerTypeHashSet>> callback);
 
   void echo(int[] value, AsyncCallback<int[]> callback);
 
   void echo(Integer[] value, AsyncCallback<Integer[]> callback);
 
+  void echo(java.sql.Date[] value, AsyncCallback<java.sql.Date[]> callback);
+
+  void echo(LinkedHashMap<String, MarkerTypeLinkedHashMap> value,
+      AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>> callback);
+
+  void echo(LinkedHashSet<MarkerTypeLinkedHashSet> value,
+      AsyncCallback<LinkedHashSet<MarkerTypeLinkedHashSet>> callback);
+
   void echo(long[] value, AsyncCallback<long[]> callback);
 
   void echo(Long[] value, AsyncCallback<Long[]> callback);
@@ -85,9 +97,9 @@
 
   void echo(Timestamp[] value, AsyncCallback<Timestamp[]> callback);
 
-  void echo(Vector<IsSerializable> value,
-      AsyncCallback<Vector<IsSerializable>> callback);
+  void echo(Vector<MarkerTypeVector> value,
+      AsyncCallback<Vector<MarkerTypeVector>> callback);
 
-  void echoArraysAsList(List<IsSerializable> value,
-      AsyncCallback<List<IsSerializable>> callback);
+  void echoArraysAsList(List<MarkerTypeArraysAsList> value,
+      AsyncCallback<List<MarkerTypeArraysAsList>> callback);
 }
diff --git a/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetFactory.java
index 71c67c2..86fa926 100644
--- a/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -26,7 +26,7 @@
 
   /**
    * Used to test an automatically serializable subclass of a manually
-   * serializable subtype
+   * serializable subtype.
    */
   public static class SerializableSubclass extends ManuallySerializedClass
       implements IsSerializable {
diff --git a/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetValidator.java
index ded6f14..cee790c 100644
--- a/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/CustomFieldSerializerTestSetValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -31,7 +31,7 @@
     return manuallySerializedClass.getA() == 4
         && manuallySerializedClass.getB() == 5
         && manuallySerializedClass.getC() == 6
-        && manuallySerializedClass.getObj().equals("bye");
+        && manuallySerializedClass.getString().equals("bye");
   }
 
   // Must be a non-null array with two == elements
diff --git a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass.java b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass.java
index 2fa58ce..28069e4 100644
--- a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass.java
+++ b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass.java
@@ -29,7 +29,7 @@
 
   private int c = 3;
 
-  private Object obj = "hello";
+  private String str = "hello";
 
   public int getA() {
     return a;
@@ -43,8 +43,8 @@
     return c;
   }
 
-  public Object getObj() {
-    return obj;
+  public String getString() {
+    return str;
   }
 
   public void setA(int a) {
@@ -59,7 +59,7 @@
     this.c = c;
   }
 
-  public void setObj(Object obj) {
-    this.obj = obj;
+  public void setString(String str) {
+    this.str = str;
   }
 }
\ No newline at end of file
diff --git a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass_CustomFieldSerializer.java b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass_CustomFieldSerializer.java
index 1c9531d..f251207 100644
--- a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass_CustomFieldSerializer.java
+++ b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedClass_CustomFieldSerializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -26,7 +26,7 @@
     instance.setA(streamReader.readInt());
     instance.setB(streamReader.readInt());
     instance.setC(streamReader.readInt());
-    instance.setObj(streamReader.readString());
+    instance.setString(streamReader.readString());
   }
 
   public static void serialize(SerializationStreamWriter streamWriter,
diff --git a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
index baa4518..ff407d0 100644
--- a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
+++ b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
@@ -25,6 +25,13 @@
  * factory.
  */
 public class ManuallySerializedImmutableClass {
+  /**
+   * Ensures that RPC will consider Date to be exposed. It will be pruned by
+   * dead code elimination.
+   */
+  @SuppressWarnings("unused")
+  private Date dateTypeExposeToSerialization;
+
   private final Date endDate;
   private final Date startDate;
 
diff --git a/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
index 5ed9176..52251c8 100644
--- a/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/RemoteServiceServletTest.java
@@ -56,7 +56,9 @@
   public void testAlternateStatusCode() {
     RemoteServiceServletTestServiceAsync service = getAsyncService();
     ((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL()
-        + "404");
+        + "servlettest/404");
+
+    delayTestFinish(TEST_DELAY);
 
     service.test(new AsyncCallback<Void>() {
 
@@ -71,7 +73,7 @@
       }
 
       public void onSuccess(Void result) {
-        fail();
+        fail("Should not have succeeded");
       }
     });
   }
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
index d5da927..8bb6dd9 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -23,36 +23,148 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Vector;
 
 /**
- * TODO: document me.
+ * Creates test collections.
  */
 public class TestSetFactory {
 
   /**
-   * TODO: document me.
+   * Base type for single-use marker types to independently check type parameter
+   * exposure in various collections.
    */
-  public static class SerializableClass implements IsSerializable {
-    IsSerializable elementRef;
+  public static class MarkerBase implements IsSerializable {
+    public String value;
 
-    IsSerializable[] elements;
-
-    public IsSerializable getElementRef() {
-      return elementRef;
+    public MarkerBase(String value) {
+      this.value = value;
     }
 
-    public IsSerializable[] getElements() {
-      return elements;
+    @Override
+    public boolean equals(Object obj) {
+      if (obj instanceof MarkerBase && obj.getClass() == this.getClass()) {
+        MarkerBase other = (MarkerBase) obj;
+        return value == other.value
+            || (value != null && value.equals(other.value));
+      }
+      return false;
     }
 
-    public void setElementRef(IsSerializable elementRef) {
-      this.elementRef = elementRef;
+    @Override
+    public int hashCode() {
+      return value.hashCode();
     }
 
-    public void setElements(IsSerializable[] elements) {
-      this.elements = elements;
+    @Override
+    public String toString() {
+      return value;
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeArrayList extends MarkerBase {
+    public MarkerTypeArrayList(String value) {
+      super(value);
+    }
+
+    MarkerTypeArrayList() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeArraysAsList extends MarkerBase {
+
+    public MarkerTypeArraysAsList(String value) {
+      super(value);
+    }
+
+    MarkerTypeArraysAsList() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeHashMap extends MarkerBase {
+
+    public MarkerTypeHashMap(String value) {
+      super(value);
+    }
+
+    MarkerTypeHashMap() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeHashSet extends MarkerBase {
+
+    public MarkerTypeHashSet(String value) {
+      super(value);
+    }
+
+    MarkerTypeHashSet() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeLinkedHashMap extends MarkerBase {
+
+    public MarkerTypeLinkedHashMap(String value) {
+      super(value);
+    }
+
+    MarkerTypeLinkedHashMap() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeLinkedHashSet extends MarkerBase {
+
+    public MarkerTypeLinkedHashSet(String value) {
+      super(value);
+    }
+
+    MarkerTypeLinkedHashSet() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeVector extends MarkerBase {
+
+    public MarkerTypeVector(String value) {
+      super(value);
+    }
+
+    MarkerTypeVector() {
+      super(null);
     }
   }
 
@@ -92,94 +204,13 @@
   }
 
   /**
-   * TODO: document me.
-   */
-  public static class SerializableList extends ArrayList implements
-      IsSerializable {
-  }
-
-  /**
-   * TODO: document me.
-   */
-  public static class SerializableMap extends HashMap implements IsSerializable {
-  }
-
-  /**
-   * TODO: document me.
-   */
-  public static class SerializableNode extends UnserializableNode implements
-      IsSerializable {
-
-    protected String data;
-
-    protected SerializableNode next;
-
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-
-      if (obj == null) {
-        return false;
-      }
-
-      if (!(obj instanceof SerializableNode)) {
-        return false;
-      }
-
-      SerializableNode other = (SerializableNode) obj;
-      if (data != other.data) {
-        if (data == null || !data.equals(other.data)) {
-          return false;
-        }
-      }
-
-      if (next != other.next) {
-        if (next == null || !next.equals(other.next)) {
-          return false;
-        }
-      }
-
-      return true;
-    }
-
-    public String getData() {
-      return data;
-    }
-
-    public SerializableNode getNext() {
-      return next;
-    }
-
-    public int hashCode() {
-      int hashValue = 0;
-      if (data != null) {
-        hashValue += data.hashCode();
-      }
-
-      if (next != null && next != this) {
-        hashValue += next.hashCode();
-      }
-
-      return hashValue;
-    }
-
-    public void setData(String data) {
-      this.data = data;
-    }
-
-    public void setNext(SerializableNode next) {
-      this.next = next;
-    }
-  }
-
-  /**
    * Tests that classes with a private no-arg constructor can be serialized.
    */
   public static class SerializablePrivateNoArg implements IsSerializable {
     private int value;
 
     public SerializablePrivateNoArg(int value) {
+      this();
       this.value = value;
     }
 
@@ -194,19 +225,6 @@
   /**
    * TODO: document me.
    */
-  public static class SerializableSet extends HashSet implements IsSerializable {
-  }
-
-  /**
-   * TODO: document me.
-   */
-  public static class SerializableVector extends Vector implements
-      IsSerializable {
-  }
-
-  /**
-   * TODO: document me.
-   */
   public static class SerializableWithTwoArrays implements IsSerializable {
     String[] one;
     String[] two;
@@ -218,6 +236,22 @@
   public static class UnserializableNode {
   }
 
+  public static ArrayList<MarkerTypeArrayList> createArrayList() {
+    ArrayList<MarkerTypeArrayList> list = new ArrayList<MarkerTypeArrayList>();
+    list.add(new MarkerTypeArrayList("foo"));
+    list.add(new MarkerTypeArrayList("bar"));
+    list.add(new MarkerTypeArrayList("baz"));
+    list.add(new MarkerTypeArrayList("bal"));
+    list.add(new MarkerTypeArrayList("w00t"));
+    return list;
+  }
+
+  public static List<MarkerTypeArraysAsList> createArraysAsList() {
+    return Arrays.asList(new MarkerTypeArraysAsList("foo"),
+        new MarkerTypeArraysAsList("bar"), new MarkerTypeArraysAsList("baz"),
+        new MarkerTypeArraysAsList("bal"), new MarkerTypeArraysAsList("w00t"));
+  }
+
   public static Boolean[] createBooleanArray() {
     return new Boolean[] {
         Boolean.valueOf(true), Boolean.valueOf(false), Boolean.valueOf(true),
@@ -236,6 +270,7 @@
         new Character(Character.MAX_VALUE), new Character(Character.MIN_VALUE)};
   }
 
+  @SuppressWarnings("deprecation")
   public static Date[] createDateArray() {
     return new Date[] {
         new Date(1992 - 1900, 9, 18), new Date(1997 - 1900, 6, 6)};
@@ -253,45 +288,23 @@
         new Float(Float.MAX_VALUE), new Float(Float.MIN_VALUE)};
   }
 
-  public static HashMap createHashMap() {
-    HashMap map = new HashMap();
-    map.put("SerializableNode", new SerializableNode());
-    map.put("SerializableList", new SerializableList());
-    map.put("SerializableMap", new SerializableMap());
-    map.put("SerializableSet", new SerializableSet());
-    map.put("SerializableVector", new SerializableVector());
+  public static HashMap<String, MarkerTypeHashMap> createHashMap() {
+    HashMap<String, MarkerTypeHashMap> map = new HashMap<String, MarkerTypeHashMap>();
+    map.put("foo", new MarkerTypeHashMap("foo"));
+    map.put("bar", new MarkerTypeHashMap("bar"));
+    map.put("baz", new MarkerTypeHashMap("baz"));
+    map.put("bal", new MarkerTypeHashMap("bal"));
+    map.put("w00t", new MarkerTypeHashMap("w00t"));
     return map;
   }
 
-  public static LinkedHashMap createLRULinkedHashMap() {
-    LinkedHashMap map = new LinkedHashMap(100, 1.0f, true);
-    map.put("SerializableNode", new SerializableNode());
-    map.put("SerializableList", new SerializableList());
-    map.put("SerializableMap", new SerializableMap());
-    map.put("SerializableSet", new SerializableSet());
-    map.put("SerializableVector", new SerializableVector());
-    map.get("SerializableMap");
-    return map;
-  }
-
-  public static LinkedHashMap createLinkedHashMap() {
-    LinkedHashMap map = new LinkedHashMap();
-    map.put("SerializableNode", new SerializableNode());
-    map.put("SerializableList", new SerializableList());
-    map.put("SerializableMap", new SerializableMap());
-    map.put("SerializableSet", new SerializableSet());
-    map.put("SerializableVector", new SerializableVector());
-    return map;
-  }
-
-  public static HashSet createHashSet() {
-    HashSet set = new HashSet();
-    set.add(new SerializableNode());
-    set.add(new SerializableList());
-    set.add(new SerializableMap());
-    set.add(new SerializableSet());
-    set.add(new SerializableVector());
-
+  public static HashSet<MarkerTypeHashSet> createHashSet() {
+    HashSet<MarkerTypeHashSet> set = new HashSet<MarkerTypeHashSet>();
+    set.add(new MarkerTypeHashSet("foo"));
+    set.add(new MarkerTypeHashSet("bar"));
+    set.add(new MarkerTypeHashSet("baz"));
+    set.add(new MarkerTypeHashSet("bal"));
+    set.add(new MarkerTypeHashSet("w00t"));
     return set;
   }
 
@@ -301,12 +314,43 @@
         new Integer(Integer.MAX_VALUE), new Integer(Integer.MIN_VALUE)};
   }
 
+  public static LinkedHashMap<String, MarkerTypeLinkedHashMap> createLinkedHashMap() {
+    LinkedHashMap<String, MarkerTypeLinkedHashMap> map = new LinkedHashMap<String, MarkerTypeLinkedHashMap>();
+    map.put("foo", new MarkerTypeLinkedHashMap("foo"));
+    map.put("bar", new MarkerTypeLinkedHashMap("bar"));
+    map.put("baz", new MarkerTypeLinkedHashMap("baz"));
+    map.put("bal", new MarkerTypeLinkedHashMap("bal"));
+    map.put("w00t", new MarkerTypeLinkedHashMap("w00t"));
+    return map;
+  }
+
+  public static LinkedHashSet<MarkerTypeLinkedHashSet> createLinkedHashSet() {
+    LinkedHashSet<MarkerTypeLinkedHashSet> set = new LinkedHashSet<MarkerTypeLinkedHashSet>();
+    set.add(new MarkerTypeLinkedHashSet("foo"));
+    set.add(new MarkerTypeLinkedHashSet("bar"));
+    set.add(new MarkerTypeLinkedHashSet("baz"));
+    set.add(new MarkerTypeLinkedHashSet("bal"));
+    set.add(new MarkerTypeLinkedHashSet("w00t"));
+    return set;
+  }
+
   public static Long[] createLongArray() {
     return new Long[] {
         new Long(Long.MAX_VALUE), new Long(Long.MIN_VALUE),
         new Long(Long.MAX_VALUE), new Long(Long.MIN_VALUE)};
   }
 
+  public static LinkedHashMap<String, MarkerTypeLinkedHashMap> createLRULinkedHashMap() {
+    LinkedHashMap<String, MarkerTypeLinkedHashMap> map = new LinkedHashMap<String, MarkerTypeLinkedHashMap>(
+        100, 1.0f, true);
+    map.put("foo", new MarkerTypeLinkedHashMap("foo"));
+    map.put("bar", new MarkerTypeLinkedHashMap("bar"));
+    map.put("baz", new MarkerTypeLinkedHashMap("baz"));
+    map.put("bal", new MarkerTypeLinkedHashMap("bal"));
+    map.put("w00t", new MarkerTypeLinkedHashMap("w00t"));
+    return map;
+  }
+
   public static boolean[] createPrimitiveBooleanArray() {
     return new boolean[] {true, true, false, false, true, false};
   }
@@ -381,13 +425,13 @@
         "valueOf", "constructor", "__proto__"};
   }
 
-  public static Vector createVector() {
-    Vector vector = new Vector();
-    vector.add(new SerializableNode());
-    vector.add(new SerializableList());
-    vector.add(new SerializableMap());
-    vector.add(new SerializableSet());
-    vector.add(new SerializableVector());
+  public static Vector<MarkerTypeVector> createVector() {
+    Vector<MarkerTypeVector> vector = new Vector<MarkerTypeVector>();
+    vector.add(new MarkerTypeVector("foo"));
+    vector.add(new MarkerTypeVector("bar"));
+    vector.add(new MarkerTypeVector("baz"));
+    vector.add(new MarkerTypeVector("bal"));
+    vector.add(new MarkerTypeVector("w00t"));
     return vector;
   }
 
@@ -411,20 +455,6 @@
     return head;
   }
 
-  static ArrayList createArrayList() {
-    ArrayList list = new ArrayList();
-    list.add(new SerializableNode());
-    list.add(new SerializableList());
-    list.add(new SerializableMap());
-    list.add(new SerializableSet());
-    list.add(new SerializableVector());
-    return list;
-  }
-
-  static List createArraysAsList() {
-    return Arrays.asList((byte) 0, (byte) 1, (byte) 2, (byte) 3);
-  }
-
   static SerializableDoublyLinkedNode createComplexCyclicGraph() {
     SerializableDoublyLinkedNode n1 = new SerializableDoublyLinkedNode();
     n1.setData("n0");
@@ -456,18 +486,6 @@
     return o;
   }
 
-  static SerializableClass createSerializableClass() {
-    SerializableClass cls = new SerializableClass();
-    IsSerializable[] elements = new IsSerializable[] {
-        new SerializableClass(), new SerializableClass(),
-        new SerializableClass(), new SerializableClass(),};
-
-    cls.setElements(elements);
-    cls.setElementRef(elements[3]);
-
-    return cls;
-  }
-
   static SerializableDoublyLinkedNode createTrivialCyclicGraph() {
     SerializableDoublyLinkedNode root = new SerializableDoublyLinkedNode();
     root.setData("head");
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
index d210669..da95a6d 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.user.client.rpc;
 
-import com.google.gwt.user.client.rpc.TestSetFactory.SerializableClass;
 import com.google.gwt.user.client.rpc.TestSetFactory.SerializableDoublyLinkedNode;
 import com.google.gwt.user.client.rpc.TestSetFactory.SerializablePrivateNoArg;
 import com.google.gwt.user.client.rpc.TestSetFactory.SerializableWithTwoArrays;
@@ -25,8 +24,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 import java.util.Map.Entry;
@@ -36,15 +35,6 @@
  */
 public class TestSetValidator {
 
-  public static boolean equals(Iterator expected, Iterator actual) {
-    while (expected.hasNext() && actual.hasNext()) {
-      if (!expected.next().equals(actual.next())) {
-        return false;
-      }
-    }
-    return expected.hasNext() == actual.hasNext();
-  }
-
   public static boolean equals(boolean[] expected, boolean[] actual) {
     if (actual == null) {
       return false;
@@ -153,6 +143,15 @@
     return true;
   }
 
+  public static boolean equals(Iterator expected, Iterator actual) {
+    while (expected.hasNext() && actual.hasNext()) {
+      if (!expected.next().equals(actual.next())) {
+        return false;
+      }
+    }
+    return expected.hasNext() == actual.hasNext();
+  }
+
   public static boolean equals(long[] expected, long[] actual) {
     if (actual == null) {
       return false;
@@ -235,28 +234,7 @@
     return reference.equals(list);
   }
 
-  public static boolean isValid(HashSet expected, HashSet actual) {
-    if (actual == null) {
-      return false;
-    }
-
-    if (expected.size() != actual.size()) {
-      return false;
-    }
-
-    Iterator entryIter = expected.iterator();
-    while (entryIter.hasNext()) {
-      Object entry = entryIter.next();
-
-      if (!actual.contains(entry)) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  public static boolean isValid(Map expected, HashMap map) {
+  public static boolean isValid(HashMap expected, HashMap map) {
     if (map == null) {
       return false;
     }
@@ -286,8 +264,29 @@
     return true;
   }
 
+  public static boolean isValid(HashSet expected, HashSet actual) {
+    if (actual == null) {
+      return false;
+    }
+
+    if (expected.size() != actual.size()) {
+      return false;
+    }
+
+    Iterator entryIter = expected.iterator();
+    while (entryIter.hasNext()) {
+      Object entry = entryIter.next();
+
+      if (!actual.contains(entry)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
   public static boolean isValid(LinkedHashMap expected, LinkedHashMap map) {
-    if (isValid((Map) expected, (HashMap) map)) {
+    if (isValid((HashMap) expected, (HashMap) map)) {
       Iterator expectedEntries = expected.entrySet().iterator();
       Iterator actualEntries = map.entrySet().iterator();
       return equals(expectedEntries, actualEntries);
@@ -295,27 +294,13 @@
     return false;
   }
 
-  public static boolean isValid(SerializableClass actual) {
-    if (actual == null) {
-      return false;
+  public static boolean isValid(LinkedHashSet expected, LinkedHashSet map) {
+    if (isValid((HashSet) expected, (HashSet) map)) {
+      Iterator expectedEntries = expected.iterator();
+      Iterator actualEntries = map.iterator();
+      return equals(expectedEntries, actualEntries);
     }
-
-    IsSerializable[] elements = actual.getElements();
-    IsSerializable elementRef = actual.getElementRef();
-
-    if (elements == null || elementRef == null) {
-      return false;
-    }
-
-    if (elements.length != 4) {
-      return false;
-    }
-
-    if (elements[3] != elementRef) {
-      return false;
-    }
-
-    return true;
+    return false;
   }
 
   public static boolean isValid(SerializablePrivateNoArg actual) {
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index 972c2b1..e72c6ec 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -30,6 +30,8 @@
 import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType;
 import com.google.gwt.dev.cfg.ModuleDef;
 import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.cfg.Property;
+import com.google.gwt.dev.cfg.StaticPropertyOracle;
 import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.javac.JavaSourceCodeBase;
 import com.google.gwt.dev.javac.MockCompilationUnit;
@@ -38,7 +40,6 @@
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.user.rebind.rpc.testcases.client.AbstractSerializableTypes;
 import com.google.gwt.user.rebind.rpc.testcases.client.ClassWithTypeParameterThatErasesToObject;
-import com.google.gwt.user.rebind.rpc.testcases.client.CovariantArrays;
 import com.google.gwt.user.rebind.rpc.testcases.client.ManualSerialization;
 import com.google.gwt.user.rebind.rpc.testcases.client.NoSerializableTypes;
 import com.google.gwt.user.rebind.rpc.testcases.client.NotAllSubtypesAreSerializable;
@@ -231,6 +232,14 @@
     return new MockCompilationUnit(qname, code.toString());
   }
 
+  private static SerializableTypeOracleBuilder createSerializableTypeOracleBuilder(
+      TreeLogger logger, TypeOracle to) throws UnableToCompleteException {
+    StaticPropertyOracle propertyOracle = new StaticPropertyOracle();
+    // PropertyOracle has no values.
+    propertyOracle.setPropertyValues(new Property[0], new String[0]);
+    return new SerializableTypeOracleBuilder(logger, propertyOracle, to);
+  }
+
   private static TypeInfo[] getActualTypeInfo(SerializableTypeOracle sto) {
     JType[] types = sto.getSerializableTypes();
     TypeInfo[] actual = new TypeInfo[types.length];
@@ -351,7 +360,7 @@
     JParameterizedType listOfCantSerialize = to.getParameterizedType(list,
         makeArray(cantSerialize));
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, listOfCantSerialize);
     SerializableTypeOracle so = sob.build(logger);
@@ -402,7 +411,7 @@
     JClassType b = to.getType("B");
     JClassType c = to.getType("C");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, b);
     SerializableTypeOracle so = sob.build(logger);
@@ -458,7 +467,7 @@
     JClassType c = to.getType("java.C");
     JArrayType arrayOfC = to.getArrayType(c);
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, arrayOfA);
     SerializableTypeOracle so = sob.build(logger);
@@ -550,7 +559,7 @@
     JClassType ser2 = to.getType("Ser2");
     JClassType root = to.getType("Root");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, root);
 
@@ -631,7 +640,7 @@
     JClassType javaLangString = to.getType(String.class.getName());
     JParameterizedType cOfString = to.getParameterizedType(c,
         makeArray(javaLangString));
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, cOfString);
 
@@ -778,7 +787,7 @@
 
     TreeLogger logger = createLogger();
     TypeOracle to = TypeOracleTestingUtils.buildTypeOracle(logger, units);
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
 
     // Does not qualify because it is not declared to be auto or manually
@@ -853,7 +862,7 @@
         ClassWithTypeParameterThatErasesToObject.class.getCanonicalName()).isGenericType().getRawType();
 
     // The raw form of the type should not be serializable.
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, rawType);
     try {
@@ -925,7 +934,7 @@
     JClassType dateHolder = to.getType("DateHolder");
     JClassType unrelatedClass = to.getType("UnrelatedClass");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, holder.getRawType());
     SerializableTypeOracle so = sob.build(logger);
@@ -949,31 +958,60 @@
    */
   public void testCovariantArrays() throws UnableToCompleteException,
       NotFoundException {
-    TreeLogger logger = createLogger();
+    Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+    addStandardClasses(units);
 
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
-        logger, typeOracle);
-    JClassType rootType = typeOracle.getArrayType(typeOracle.getType(CovariantArrays.AA.class.getCanonicalName()));
-    stob.addRootType(logger, rootType);
+    {
+      StringBuilder code = new StringBuilder();
+      code.append("import java.io.Serializable;\n");
+      code.append("public class Sup implements Serializable {\n");
+      code.append("}\n");
+      units.add(createMockCompilationUnit("Sup", code));
+    }
+
+    {
+      StringBuilder code = new StringBuilder();
+      code.append("import java.io.Serializable;\n");
+      code.append("public class Sub extends Sup {\n");
+      code.append("}\n");
+      units.add(createMockCompilationUnit("Sub", code));
+    }
+
+    TreeLogger logger = createLogger();
+    TypeOracle to = TypeOracleTestingUtils.buildTypeOracle(logger, units);
+
+    JClassType sup = to.getType("Sup");
+    JClassType sub = to.getType("Sub");
+    JPrimitiveType primFloat = JPrimitiveType.FLOAT;
+
+    JArrayType subArray = to.getArrayType(sub);
+    JArrayType subArrayArray = to.getArrayType(subArray);
+    JArrayType supArray = to.getArrayType(sup);
+    JArrayType supArrayArray = to.getArrayType(supArray);
+    JArrayType primFloatArray = to.getArrayType(primFloat);
+    JArrayType primFloatArrayArray = to.getArrayType(primFloatArray);
+
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
+        logger, to);
+    // adding Sub first exercises an extra code path in STOB
+    stob.addRootType(logger, sub);
+    stob.addRootType(logger, supArrayArray);
+    stob.addRootType(logger, primFloatArrayArray);
     SerializableTypeOracle sto = stob.build(logger);
 
-    TypeInfo[] expected = new TypeInfo[] {
-        new TypeInfo(CovariantArrays.AA.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.BB.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.CC.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.DD.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.A.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.B.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.B.class.getName(), true),
-        new TypeInfo(CovariantArrays.C.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.D.class.getName() + "[]", true),
-        new TypeInfo(CovariantArrays.D.class.getName(), true),};
-    validateSTO(sto, expected);
+    assertSerializableTypes(sto, sup, sub, supArray, subArray, primFloatArray,
+        supArrayArray, subArrayArray, primFloatArrayArray);
+    assertInstantiable(sto, primFloatArrayArray);
+    assertInstantiable(sto, primFloatArray);
+    assertInstantiable(sto, subArrayArray);
+    assertInstantiable(sto, subArray);
+    assertInstantiable(sto, supArrayArray);
+    assertInstantiable(sto, supArray);
   }
 
   /**
    * If the query type extends a raw type, be sure to pick up the parameters of
-   * the raw supertype.
+   * the raw subertype.
    * 
    * @throws UnableToCompleteException
    * @throws NotFoundException
@@ -1024,7 +1062,7 @@
     JClassType serClass = to.getType("SerClass");
     JClassType serClassSub = to.getType("SerClassSub");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, nameSet);
     SerializableTypeOracle so = sob.build(logger);
@@ -1110,7 +1148,7 @@
     JParameterizedType hashSetOfString = to.getParameterizedType(hashSet,
         makeArray(string));
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, hashSetOfString);
     SerializableTypeOracle so = sob.build(logger);
@@ -1171,7 +1209,7 @@
 
     JParameterizedType aOfString = to.getParameterizedType(a,
         makeArray(serializableArgument));
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, aOfString);
     SerializableTypeOracle so = sob.build(logger);
@@ -1226,7 +1264,7 @@
 
     JParameterizedType aOfString = to.getParameterizedType(a,
         makeArray(unusedSerializableArgument));
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, aOfString);
     SerializableTypeOracle so = sob.build(logger);
@@ -1274,7 +1312,7 @@
     JClassType javaLangString = to.getType(String.class.getName());
     JParameterizedType aOfString = to.getParameterizedType(a,
         makeArray(javaLangString));
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, aOfString);
     SerializableTypeOracle so = sob.build(logger);
@@ -1322,7 +1360,7 @@
     JClassType javaLangString = to.getType(String.class.getName());
     JParameterizedType aOfString = to.getParameterizedType(a,
         makeArray(javaLangString));
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
 
     assertEquals(EXPOSURE_DIRECT, sob.getTypeParameterExposure(a, 0));
@@ -1348,7 +1386,7 @@
       UnableToCompleteException {
     TreeLogger logger = createLogger();
 
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     JClassType a = typeOracle.getType(ManualSerialization.A.class.getCanonicalName());
     JClassType b = typeOracle.getType(ManualSerialization.B.class.getCanonicalName());
@@ -1367,7 +1405,7 @@
     TreeLogger logger = createLogger();
 
     JClassType rawList = typeOracle.getType(List.class.getName());
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, rawList);
     SerializableTypeOracle sto = stob.build(logger);
@@ -1492,7 +1530,7 @@
     JParameterizedType parameterizedListOfIntf1 = to.getParameterizedType(list,
         makeArray(intf1));
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, parameterizedListOfIntf1);
     SerializableTypeOracle so = sob.build(logger);
@@ -1511,7 +1549,7 @@
     TreeLogger logger = createLogger();
 
     JClassType a = typeOracle.getType(NoSerializableTypes.A.class.getCanonicalName());
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, a);
     try {
@@ -1532,7 +1570,7 @@
     TreeLogger logger = createLogger();
 
     JClassType a = typeOracle.getType(NotAllSubtypesAreSerializable.A.class.getCanonicalName());
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, a);
     SerializableTypeOracle sto = stob.build(logger);
@@ -1554,7 +1592,7 @@
     TreeLogger logger = createLogger();
 
     JArrayType objectArray = typeOracle.getArrayType(typeOracle.getJavaLangObject());
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, objectArray);
     try {
@@ -1571,7 +1609,7 @@
   public void testObjectNotInstantiable() throws UnableToCompleteException {
     TreeLogger logger = createLogger();
 
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(logger, typeOracle.getJavaLangObject());
     try {
@@ -1590,7 +1628,7 @@
       throws UnableToCompleteException, NotFoundException {
     TreeLogger logger = createLogger();
 
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, typeOracle);
     stob.addRootType(
         logger,
@@ -1655,7 +1693,7 @@
     JGenericType linkedList = to.getType("LinkedList").isGenericType();
     JClassType randomClass = to.getType("RandomClass");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, list.getRawType());
     SerializableTypeOracle so = sob.build(logger);
@@ -1701,7 +1739,7 @@
 
     JClassType serializableClass = to.getType("SerializableClass");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, rawA);
     SerializableTypeOracle so = sob.build(logger);
@@ -1738,7 +1776,7 @@
     JClassType rawA = a.getRawType();
     JTypeParameter ta = a.getTypeParameters()[0];
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, ta);
     SerializableTypeOracle so = sob.build(logger);
@@ -1801,7 +1839,7 @@
     JClassType javaLangString = to.getType(String.class.getName());
     JParameterizedType aOfString = to.getParameterizedType(a,
         makeArray(javaLangString));
-    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
         logger, to);
     stob.addRootType(logger, aOfString);
 
@@ -1861,7 +1899,7 @@
     JRawType rawB = to.getType("B").isGenericType().getRawType();
     JClassType c = to.getType("C");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, a);
     SerializableTypeOracle so = sob.build(logger);
@@ -1925,7 +1963,7 @@
         new JClassType[] {to.getType(String.class.getName())});
     JClassType ser = to.getType("Ser");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, intfOfString);
     SerializableTypeOracle so = sob.build(logger);
@@ -1973,7 +2011,7 @@
 
     JClassType a = to.getType("A");
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, a);
     SerializableTypeOracle so = sob.build(logger);
@@ -2150,7 +2188,7 @@
 
     JParameterizedType parameterizedType = to.getParameterizedType(a,
         new JClassType[] {syntheticTypeParam});
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, parameterizedType);
     SerializableTypeOracle so = sob.build(logger);
@@ -2205,7 +2243,7 @@
     JTypeParameter u = a.getTypeParameters()[0];
     JTypeParameter v = a.getMethod("getFoo", makeArray()).getReturnType().isTypeParameter();
 
-    SerializableTypeOracleBuilder sob = new SerializableTypeOracleBuilder(
+    SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(
         logger, to);
     sob.addRootType(logger, u);
     sob.addRootType(logger, v);
diff --git a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java
deleted file mode 100644
index f4f5c6b..0000000
--- a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/CovariantArrays.java
+++ /dev/null
@@ -1,85 +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.user.rebind.rpc.testcases.client;
-
-import com.google.gwt.user.client.rpc.IsSerializable;
-
-/**
- * Used to test that the
- * {@link com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilder SerializableTypeOracleBuilder}
- * will handle covariant arrays correctly. For example, the service interface
- * below should be able to handle the following covariant array types: AA[],
- * A[], BB[], B[], CC[], C[], DD[], D[]. Notice that E[] should not be included.
- */
-public interface CovariantArrays {
-  /**
-   * Not serializable.
-   */
-  class A implements DD {
-  }
-
-  /**
-   * Not serializable.
-   */
-  interface AA {
-  }
-
-  /**
-   * Auto serializable.
-   */
-  class B extends A implements IsSerializable {
-  }
-
-  /**
-   * Not serializable.
-   */
-  interface BB extends AA {
-  }
-
-  /**
-   * Not auto serializable due to bad field.
-   */
-  class C extends B {
-    Object field;
-  }
-
-  /**
-   * Not serializable.
-   */
-  interface CC extends AA {
-  }
-
-  /**
-   * Auto serializable.
-   */
-  class D extends C implements IsSerializable {
-  }
-
-  /**
-   * Not serializable.
-   */
-  interface DD extends BB, CC {
-  }
-
-  /**
-   * Not auto serializable because super class is not.
-   */
-  class E extends C {
-  }
-
-  AA[] getAs();
-}
diff --git a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
index cd61558..12bd35b 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -18,6 +18,13 @@
 import com.google.gwt.user.client.rpc.CollectionsTestService;
 import com.google.gwt.user.client.rpc.TestSetFactory;
 import com.google.gwt.user.client.rpc.TestSetValidator;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArrayList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArraysAsList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
 
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -27,6 +34,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Vector;
 
@@ -40,8 +48,8 @@
     return Arrays.asList(values).toString();
   }
 
-  @SuppressWarnings("unchecked")
-  public ArrayList echo(ArrayList list) throws CollectionsTestServiceException {
+  public ArrayList<MarkerTypeArrayList> echo(ArrayList<MarkerTypeArrayList> list)
+      throws CollectionsTestServiceException {
     if (!TestSetValidator.isValid(list)) {
       throw new CollectionsTestServiceException();
     }
@@ -122,17 +130,6 @@
     return actual;
   }
 
-  public java.sql.Date[] echo(java.sql.Date[] actual)
-      throws CollectionsTestServiceException {
-    java.sql.Date[] expected = TestSetFactory.createSqlDateArray();
-    if (!TestSetValidator.equals(expected, actual)) {
-      throw new CollectionsTestServiceException("expected: "
-          + toString(expected) + " actual: " + toString(actual));
-    }
-
-    return actual;
-  }
-
   public double[] echo(double[] actual) throws CollectionsTestServiceException {
     double[] expected = TestSetFactory.createPrimitiveDoubleArray();
     if (!TestSetValidator.equals(expected, actual)) {
@@ -173,9 +170,10 @@
     return actual;
   }
 
-  @SuppressWarnings("unchecked")
-  public HashMap echo(HashMap actual) throws CollectionsTestServiceException {
-    HashMap expected = TestSetFactory.createHashMap();
+  public HashMap<String, MarkerTypeHashMap> echo(
+      HashMap<String, MarkerTypeHashMap> actual)
+      throws CollectionsTestServiceException {
+    HashMap<String, MarkerTypeHashMap> expected = TestSetFactory.createHashMap();
     if (!TestSetValidator.isValid(expected, actual)) {
       throw new CollectionsTestServiceException("expected: "
           + expected.toString() + " actual: " + actual.toString());
@@ -184,20 +182,9 @@
     return actual;
   }
 
-  @SuppressWarnings("unchecked")
-  public LinkedHashMap echo(LinkedHashMap actual)
+  public HashSet<MarkerTypeHashSet> echo(HashSet<MarkerTypeHashSet> actual)
       throws CollectionsTestServiceException {
-    HashMap expected = TestSetFactory.createLinkedHashMap();
-    if (!TestSetValidator.isValid(expected, actual)) {
-      throw new CollectionsTestServiceException("expected:"
-          + expected.toString() + " actual:" + actual.toString());
-    }
-    return actual;
-  }
-
-  @SuppressWarnings("unchecked")
-  public HashSet echo(HashSet actual) throws CollectionsTestServiceException {
-    HashSet expected = TestSetFactory.createHashSet();
+    HashSet<MarkerTypeHashSet> expected = TestSetFactory.createHashSet();
     if (!TestSetValidator.isValid(expected, actual)) {
       throw new CollectionsTestServiceException("expected: "
           + expected.toString() + " actual: " + actual.toString());
@@ -232,6 +219,39 @@
     return actual;
   }
 
+  public java.sql.Date[] echo(java.sql.Date[] actual)
+      throws CollectionsTestServiceException {
+    java.sql.Date[] expected = TestSetFactory.createSqlDateArray();
+    if (!TestSetValidator.equals(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + toString(expected) + " actual: " + toString(actual));
+    }
+
+    return actual;
+  }
+
+  public LinkedHashMap<String, MarkerTypeLinkedHashMap> echo(
+      LinkedHashMap<String, MarkerTypeLinkedHashMap> actual)
+      throws CollectionsTestServiceException {
+    LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLinkedHashMap();
+    if (!TestSetValidator.isValid(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + expected.toString() + " actual: " + actual.toString());
+    }
+    return actual;
+  }
+
+  public LinkedHashSet<MarkerTypeLinkedHashSet> echo(
+      LinkedHashSet<MarkerTypeLinkedHashSet> actual)
+      throws CollectionsTestServiceException {
+    LinkedHashSet<MarkerTypeLinkedHashSet> expected = TestSetFactory.createLinkedHashSet();
+    if (!TestSetValidator.isValid(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + expected.toString() + " actual: " + actual.toString());
+    }
+    return actual;
+  }
+
   public long[] echo(long[] actual) throws CollectionsTestServiceException {
     long[] expected = TestSetFactory.createPrimitiveLongArray();
     if (!TestSetValidator.equals(expected, actual)) {
@@ -308,9 +328,9 @@
     return actual;
   }
 
-  @SuppressWarnings("unchecked")
-  public Vector echo(Vector actual) throws CollectionsTestServiceException {
-    Vector expected = TestSetFactory.createVector();
+  public Vector<MarkerTypeVector> echo(Vector<MarkerTypeVector> actual)
+      throws CollectionsTestServiceException {
+    Vector<MarkerTypeVector> expected = TestSetFactory.createVector();
     if (!TestSetValidator.isValid(expected, actual)) {
       throw new CollectionsTestServiceException("expected: "
           + expected.toString() + " actual: " + actual.toString());
@@ -319,12 +339,8 @@
     return actual;
   }
 
-  /**
-   * Return the result of Arrays.asList(Object[]) to force an
-   * InvocationException on the client.
-   */
-  @SuppressWarnings("unchecked")
-  public List echoArraysAsList(List value)
+  public List<MarkerTypeArraysAsList> echoArraysAsList(
+      List<MarkerTypeArraysAsList> value)
       throws CollectionsTestServiceException {
     if (!TestSetValidator.isValidAsList(value)) {
       throw new CollectionsTestServiceException();
diff --git a/user/test/com/google/gwt/user/server/rpc/CustomFieldSerializerTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CustomFieldSerializerTestServiceImpl.java
index 46205ba..ea5d3ce 100644
--- a/user/test/com/google/gwt/user/server/rpc/CustomFieldSerializerTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CustomFieldSerializerTestServiceImpl.java
@@ -17,10 +17,13 @@
 
 import com.google.gwt.user.client.rpc.CustomFieldSerializerTestService;
 import com.google.gwt.user.client.rpc.CustomFieldSerializerTestSetValidator;
+import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
 import com.google.gwt.user.client.rpc.ManuallySerializedClass;
 import com.google.gwt.user.client.rpc.ManuallySerializedImmutableClass;
 import com.google.gwt.user.client.rpc.CustomFieldSerializerTestSetFactory.SerializableSubclass;
 
+import javax.servlet.ServletContext;
+
 /**
  * Servlet used by the
  * {@link com.google.gwt.user.client.rpc.CustomFieldSerializerTest CustomFieldSerializerTest}
@@ -29,6 +32,12 @@
 public class CustomFieldSerializerTestServiceImpl extends RemoteServiceServlet
     implements CustomFieldSerializerTestService {
 
+  /**
+   * Filters log messages to avoid logging spurious warnings during successful
+   * tests.
+   */
+  private ServletContext wrappedServletContext;
+
   public ManuallySerializedClass echo(
       ManuallySerializedClass unserializableClass) {
     if (!CustomFieldSerializerTestSetValidator.isValid(unserializableClass)) {
@@ -54,4 +63,26 @@
 
     return serializableClass;
   }
+
+  /**
+   * Overrides the default servlet context to filter expected log messages.
+   */
+  @Override
+  public ServletContext getServletContext() {
+    if (wrappedServletContext == null) {
+      wrappedServletContext = new LogFilterServletContext(
+          super.getServletContext()) {
+        @Override
+        protected boolean shouldLog(Throwable t, String msg) {
+          if (t instanceof IncompatibleRemoteServiceException
+              && t.getMessage().contains(
+                  "com.google.gwt.user.client.rpc.CustomFieldSerializerTestSetFactory$UnserializableSubclass")) {
+            return false;
+          }
+          return true;
+        }
+      };
+    }
+    return wrappedServletContext;
+  }
 }
diff --git a/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
index 77545da..5292afd 100644
--- a/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/InheritanceTestServiceImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -15,17 +15,21 @@
  */
 package com.google.gwt.user.server.rpc;
 
+import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
+import com.google.gwt.user.client.rpc.InheritanceTestServiceSubtype;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory;
 import com.google.gwt.user.client.rpc.InheritanceTestSetValidator;
-import com.google.gwt.user.client.rpc.InheritanceTestServiceSubtype;
+import com.google.gwt.user.client.rpc.SerializationException;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.AbstractClass;
-import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.MySerializableInterface;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.AnonymousClassInterface;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.Circle;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.JavaSerializableClass;
+import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.MySerializableInterface;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.SerializableClass;
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.SerializableClassWithTransientField;
 
+import javax.servlet.ServletContext;
+
 /**
  * Servlet used by the
  * {@link com.google.gwt.user.client.rpc.InheritanceTest InheritanceTest} unit
@@ -34,6 +38,12 @@
 public class InheritanceTestServiceImpl extends RemoteServiceServlet implements
     InheritanceTestServiceSubtype {
 
+  /**
+   * Filters log messages to avoid logging spurious warnings during successful
+   * tests.
+   */
+  private ServletContext wrappedServletContext;
+
   public AnonymousClassInterface echo(AnonymousClassInterface serializable) {
     return serializable;
   }
@@ -85,6 +95,29 @@
     return null;
   }
 
+  /**
+   * Overrides the default servlet context to filter expected log messages.
+   */
+  @Override
+  public ServletContext getServletContext() {
+    if (wrappedServletContext == null) {
+      wrappedServletContext = new LogFilterServletContext(
+          super.getServletContext()) {
+        @Override
+        protected boolean shouldLog(Throwable t, String msg) {
+          if ((t instanceof IncompatibleRemoteServiceException || t instanceof SerializationException)
+              && (t.getMessage().contains("com.google.gwt.user.client.rpc.InheritanceTest$1"))
+              || t.getMessage().contains(
+                  "com.google.gwt.user.client.rpc.InheritanceTestSetFactory$1")) {
+            return false;
+          }
+          return true;
+        }
+      };
+    }
+    return wrappedServletContext;
+  }
+
   public SerializableClass getUnserializableClass() {
     return InheritanceTestSetFactory.createNonStaticInnerClass();
   }
diff --git a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
index 04fefc9..c881d1b 100644
--- a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTest.java
@@ -20,18 +20,13 @@
 
 import junit.framework.TestCase;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.security.Principal;
 import java.util.Enumeration;
-import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 import javax.servlet.RequestDispatcher;
@@ -39,10 +34,6 @@
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
 
 /**
  * Test some of the failure modes associated with
@@ -61,224 +52,14 @@
   private static class Foo implements IsSerializable {
   }
 
-  private static class MockHttpServletRequest implements HttpServletRequest {
+  private class MockHttpServletRequestContextPath extends
+      MockHttpServletRequest {
     private String contextPath;
-
-    public Object getAttribute(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Enumeration getAttributeNames() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getAuthType() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getCharacterEncoding() {
-      throw new UnsupportedOperationException();
-    }
-
-    public int getContentLength() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getContentType() {
-      throw new UnsupportedOperationException();
-    }
-
+    
+    @Override
     public String getContextPath() {
       return contextPath;
     }
-
-    public Cookie[] getCookies() {
-      throw new UnsupportedOperationException();
-    }
-
-    public long getDateHeader(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getHeader(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Enumeration getHeaderNames() {
-      throw new UnsupportedOperationException();
-    }
-
-    public Enumeration getHeaders(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public ServletInputStream getInputStream() throws IOException {
-      throw new UnsupportedOperationException();
-    }
-
-    public int getIntHeader(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getLocalAddr() {
-      throw new UnsupportedOperationException();
-    }
-
-    public Locale getLocale() {
-      throw new UnsupportedOperationException();
-    }
-
-    public Enumeration getLocales() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getLocalName() {
-      throw new UnsupportedOperationException();
-    }
-
-    public int getLocalPort() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getMethod() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getParameter(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Map getParameterMap() {
-      throw new UnsupportedOperationException();
-    }
-
-    public Enumeration getParameterNames() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String[] getParameterValues(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getPathInfo() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getPathTranslated() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getProtocol() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getQueryString() {
-      throw new UnsupportedOperationException();
-    }
-
-    public BufferedReader getReader() throws IOException {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRealPath(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRemoteAddr() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRemoteHost() {
-      throw new UnsupportedOperationException();
-    }
-
-    public int getRemotePort() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRemoteUser() {
-      throw new UnsupportedOperationException();
-    }
-
-    public RequestDispatcher getRequestDispatcher(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRequestedSessionId() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getRequestURI() {
-      throw new UnsupportedOperationException();
-    }
-
-    public StringBuffer getRequestURL() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getScheme() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getServerName() {
-      throw new UnsupportedOperationException();
-    }
-
-    public int getServerPort() {
-      throw new UnsupportedOperationException();
-    }
-
-    public String getServletPath() {
-      throw new UnsupportedOperationException();
-    }
-
-    public HttpSession getSession() {
-      throw new UnsupportedOperationException();
-    }
-
-    public HttpSession getSession(boolean arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Principal getUserPrincipal() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isRequestedSessionIdFromCookie() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isRequestedSessionIdFromUrl() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isRequestedSessionIdFromURL() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isRequestedSessionIdValid() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isSecure() {
-      throw new UnsupportedOperationException();
-    }
-
-    public boolean isUserInRole(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void removeAttribute(String arg0) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void setAttribute(String arg0, Object arg1) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void setCharacterEncoding(String arg0) {
-      throw new UnsupportedOperationException();
-    }
   }
 
   private class MockServletConfig implements ServletConfig {
@@ -427,7 +208,7 @@
 
     RemoteServiceServlet rss = new RemoteServiceServlet();
 
-    MockHttpServletRequest mockRequest = new MockHttpServletRequest();
+    MockHttpServletRequestContextPath mockRequest = new MockHttpServletRequestContextPath();
     rss.init(mockConfig);
 
     mockRequest.contextPath = "/MyModule";
@@ -455,7 +236,7 @@
 
     RemoteServiceServlet rss = new RemoteServiceServlet();
 
-    MockHttpServletRequest mockRequest = new MockHttpServletRequest();
+    MockHttpServletRequestContextPath mockRequest = new MockHttpServletRequestContextPath();
     rss.init(mockConfig);
 
     mockRequest.contextPath = "/foo";
@@ -498,7 +279,7 @@
 
     RemoteServiceServlet rss = new RemoteServiceServlet();
 
-    MockHttpServletRequest mockRequest = new MockHttpServletRequest();
+    MockHttpServletRequestContextPath mockRequest = new MockHttpServletRequestContextPath();
     rss.init(mockConfig);
 
     mockRequest.contextPath = "/MyModule";
diff --git a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTestServiceImpl.java
index ba11a06..7c7e3d5 100644
--- a/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/RemoteServiceServletTestServiceImpl.java
@@ -15,9 +15,29 @@
  */
 package com.google.gwt.user.server.rpc;
 
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 /**
  * TODO: document me.
  */
 public class RemoteServiceServletTestServiceImpl extends
     RemoteServiceServletTestServiceImplBase {
+  /**
+   * Explicitly return a 404 for the "404" URL.
+   */
+  @Override
+  protected void service(HttpServletRequest req, HttpServletResponse resp)
+      throws ServletException, IOException {
+    if (req.getPathInfo() != null && req.getPathInfo().endsWith("404")) {
+      resp.sendError(HttpServletResponse.SC_NOT_FOUND,
+          "Intentionally not found URL");
+      return;
+    }
+    super.service(req, resp);
+  }
+
 }