Fixes a typo in GWT emulation of java.util.IdentityHashSet that
prevented it from serializing succesfully. Also adds a unit test for
serialization of this class.

Review at http://gwt-code-reviews.appspot.com/1395804


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9983 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/event/shared/UmbrellaException.java b/user/src/com/google/gwt/event/shared/UmbrellaException.java
index d9ad116..134af51 100644
--- a/user/src/com/google/gwt/event/shared/UmbrellaException.java
+++ b/user/src/com/google/gwt/event/shared/UmbrellaException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.event.shared;
 
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -30,6 +31,13 @@
    */
   private Set<Throwable> causes;
 
+  /*
+   * The default constructor enables RPC support.
+   */
+  public UmbrellaException() {
+    this(new HashSet<Throwable>());
+  }
+  
   public UmbrellaException(Set<Throwable> causes) {
     super(
         "One or more exceptions caught, see full set in UmbrellaException#getCauses",
diff --git a/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java b/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
index a7dfa48..94ccf4c 100644
--- a/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -42,7 +42,7 @@
    * pruned by dead code elimination.
    */
   @SuppressWarnings("unused")
-  private K exposeValue;
+  private V exposeValue;
 
   public IdentityHashMap() {
   }
diff --git a/user/test/com/google/gwt/user/RPCSuite.gwt.xml b/user/test/com/google/gwt/user/RPCSuite.gwt.xml
index 7dd3872..dcb1a86 100644
--- a/user/test/com/google/gwt/user/RPCSuite.gwt.xml
+++ b/user/test/com/google/gwt/user/RPCSuite.gwt.xml
@@ -25,6 +25,8 @@
     class='com.google.gwt.user.server.rpc.CustomFieldSerializerTestServiceImpl' />
   <servlet path='/enums'
     class='com.google.gwt.user.server.rpc.EnumsTestServiceImpl' />
+  <servlet path='/exceptions'
+    class='com.google.gwt.user.server.rpc.ExceptionsTestServiceImpl' />
   <servlet path='/inheritance'
     class='com.google.gwt.user.server.rpc.InheritanceTestServiceImpl' />
   <servlet path='/objectgraphs'
diff --git a/user/test/com/google/gwt/user/RPCSuite.java b/user/test/com/google/gwt/user/RPCSuite.java
index c11481c..42a0881 100644
--- a/user/test/com/google/gwt/user/RPCSuite.java
+++ b/user/test/com/google/gwt/user/RPCSuite.java
@@ -32,6 +32,7 @@
 import com.google.gwt.user.client.rpc.CustomFieldSerializerTestWithTypeObfuscation;
 import com.google.gwt.user.client.rpc.EnumsTest;
 import com.google.gwt.user.client.rpc.EnumsTestWithTypeObfuscation;
+import com.google.gwt.user.client.rpc.ExceptionsTest;
 import com.google.gwt.user.client.rpc.FailedRequestTest;
 import com.google.gwt.user.client.rpc.FailingRequestBuilderTest;
 import com.google.gwt.user.client.rpc.InheritanceTest;
@@ -102,6 +103,7 @@
     suite.addTestSuite(InheritanceTest.class);
     suite.addTestSuite(CollectionsTest.class);
     suite.addTestSuite(CustomFieldSerializerTest.class);
+    suite.addTestSuite(ExceptionsTest.class);
     suite.addTestSuite(ObjectGraphTest.class);
     suite.addTestSuite(com.google.gwt.user.client.rpc.RemoteServiceServletTest.class);
     suite.addTestSuite(RpcTokenTest.class);
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 b3643d1..b01ed5e 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -18,10 +18,20 @@
 import com.google.gwt.core.client.GWT;
 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.MarkerTypeEmpty;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
 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.MarkerTypeIdentityHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedList;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
@@ -34,7 +44,10 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -238,12 +251,12 @@
     CollectionsTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
     service.echo(TestSetFactory.createEmptyList(),
-        new AsyncCallback<List<MarkerTypeEmpty>>() {
+        new AsyncCallback<List<MarkerTypeEmptyList>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(List<MarkerTypeEmpty> result) {
+          public void onSuccess(List<MarkerTypeEmptyList> result) {
             assertNotNull(result);
             assertTrue(TestSetValidator.isValid(result));
             finishTest();
@@ -255,12 +268,12 @@
     CollectionsTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
     service.echo(TestSetFactory.createEmptyMap(),
-        new AsyncCallback<Map<MarkerTypeEmpty, MarkerTypeEmpty>>() {
+        new AsyncCallback<Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(Map<MarkerTypeEmpty, MarkerTypeEmpty> result) {
+          public void onSuccess(Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> result) {
             assertNotNull(result);
             assertTrue(TestSetValidator.isValid(result));
             finishTest();
@@ -272,12 +285,12 @@
     CollectionsTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
     service.echo(TestSetFactory.createEmptySet(),
-        new AsyncCallback<Set<MarkerTypeEmpty>>() {
+        new AsyncCallback<Set<MarkerTypeEmptySet>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(Set<MarkerTypeEmpty> result) {
+          public void onSuccess(Set<MarkerTypeEmptySet> result) {
             assertNotNull(result);
             assertTrue(TestSetValidator.isValid(result));
             finishTest();
@@ -331,15 +344,15 @@
 
   public void testHashMap() {
     CollectionsTestServiceAsync service = getServiceAsync();
-    final HashMap<String, MarkerTypeHashMap> expected = TestSetFactory.createHashMap();
+    final HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> expected = TestSetFactory.createHashMap();
     delayTestFinishForRpc();
     service.echo(expected,
-        new AsyncCallback<HashMap<String, MarkerTypeHashMap>>() {
+        new AsyncCallback<HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
-          public void onSuccess(HashMap<String, MarkerTypeHashMap> result) {
+          public void onSuccess(HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> result) {
             assertNotNull(result);
             assertTrue(TestSetValidator.isValid(expected, result));
             finishTest();
@@ -364,6 +377,47 @@
     });
   }
 
+  public void testIdentityHashMapEnumKey() {
+    CollectionsTestServiceAsync service = getServiceAsync();
+    final IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> expected =
+        TestSetFactory.createIdentityHashMapEnumKey();
+    delayTestFinishForRpc();
+    service.echoEnumKey(expected,
+        new AsyncCallback<IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue>>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
+
+          public void onSuccess(IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> result) {
+            assertNotNull(result);
+            assertTrue(TestSetValidator.isValidEnumKey(expected, result));
+            finishTest();
+          }
+        });
+  }
+
+  public void testIdentityHashMap() {
+    CollectionsTestServiceAsync service = getServiceAsync();
+    final IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> expected =
+        TestSetFactory.createIdentityHashMap();
+    delayTestFinishForRpc();
+    service
+        .echo(
+            expected,
+            new AsyncCallback<IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>>() {
+              public void onFailure(Throwable caught) {
+                TestSetValidator.rethrowException(caught);
+              }
+
+              public void onSuccess(
+                  IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> result) {
+                assertNotNull(result);
+                assertTrue(TestSetValidator.isValid(expected, result));
+                finishTest();
+              }
+            });
+  }
+
   public void testIntegerArray() {
     CollectionsTestServiceAsync service = getServiceAsync();
     final Integer[] expected = TestSetFactory.createIntegerArray();
@@ -389,18 +443,19 @@
   public void testLinkedHashMap() {
     CollectionsTestServiceAsync service = getServiceAsync();
 
-    final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLinkedHashMap();
+    final LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> expected =
+        TestSetFactory.createLinkedHashMap();
     assertFalse(LinkedHashMap_CustomFieldSerializer.getAccessOrderNoReflection(expected));
 
     delayTestFinishForRpc();
     service.echo(expected,
-        new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() {
+        new AsyncCallback<LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
           public void onSuccess(
-              LinkedHashMap<String, MarkerTypeLinkedHashMap> result) {
+              LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> result) {
             assertNotNull(result);
             expected.get("SerializableSet");
             result.get("SerializableSet");
@@ -413,18 +468,19 @@
   public void testLinkedHashMapLRU() {
     CollectionsTestServiceAsync service = getServiceAsync();
 
-    final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLRULinkedHashMap();
+    final LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> expected =
+        TestSetFactory.createLRULinkedHashMap();
     assertTrue(LinkedHashMap_CustomFieldSerializer.getAccessOrderNoReflection(expected));
 
     delayTestFinishForRpc();
     service.echo(expected,
-        new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() {
+        new AsyncCallback<LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>>() {
           public void onFailure(Throwable caught) {
             TestSetValidator.rethrowException(caught);
           }
 
           public void onSuccess(
-              LinkedHashMap<String, MarkerTypeLinkedHashMap> actual) {
+              LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> actual) {
             assertNotNull(actual);
             expected.get("SerializableSet");
             actual.get("SerializableSet");
@@ -434,6 +490,42 @@
         });
   }
 
+  public void testLinkedHashSet() {
+    CollectionsTestServiceAsync service = getServiceAsync();
+    final LinkedHashSet<MarkerTypeLinkedHashSet> expected = TestSetFactory.createLinkedHashSet();
+    delayTestFinishForRpc();
+    service.echo(expected,
+        new AsyncCallback<LinkedHashSet<MarkerTypeLinkedHashSet>>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
+
+          public void onSuccess(
+              LinkedHashSet<MarkerTypeLinkedHashSet> result) {
+            assertNotNull(result);
+            assertTrue(TestSetValidator.isValid(expected, result));
+            finishTest();
+          }
+        });
+  }
+
+  public void testLinkedList() {
+    CollectionsTestServiceAsync service = getServiceAsync();
+    final LinkedList<MarkerTypeLinkedList> expected = TestSetFactory.createLinkedList();
+    delayTestFinishForRpc();
+    service.echo(expected, new AsyncCallback<LinkedList<MarkerTypeLinkedList>>() {
+      public void onFailure(Throwable caught) {
+        TestSetValidator.rethrowException(caught);
+      }
+
+      public void onSuccess(LinkedList<MarkerTypeLinkedList> result) {
+        assertNotNull(result);
+        assertTrue(TestSetValidator.isValid(expected, result));
+        finishTest();
+      }
+    });
+  }
+
   public void testLongArray() {
     CollectionsTestServiceAsync service = getServiceAsync();
     final Long[] expected = TestSetFactory.createLongArray();
@@ -798,9 +890,8 @@
 
   private CollectionsTestServiceAsync getServiceAsync() {
     if (collectionsTestService == null) {
-      collectionsTestService = (CollectionsTestServiceAsync) GWT.create(CollectionsTestService.class);
-      ((ServiceDefTarget) collectionsTestService).setServiceEntryPoint(GWT.getModuleBaseURL()
-          + "collections");
+      collectionsTestService =
+          (CollectionsTestServiceAsync) GWT.create(CollectionsTestService.class);
     }
     return collectionsTestService;
   }
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 8ae7c93..a82b60b 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -17,11 +17,20 @@
 
 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.MarkerTypeEmpty;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
 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.MarkerTypeIdentityHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapValue;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedList;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
@@ -33,8 +42,10 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -43,12 +54,13 @@
 import java.util.Vector;
 
 /**
- * TODO: document me.
+ * The Remote Service for testing GWT RPC for Collections.
  */
+@RemoteServiceRelativePath("collections")
 public interface CollectionsTestService extends RemoteService {
 
   /**
-   * TODO: document me.
+   * A custom exception for the Collection test.
    */
   final class CollectionsTestServiceException extends Exception {
     public CollectionsTestServiceException() {
@@ -63,16 +75,16 @@
       throws CollectionsTestServiceException;
 
   // For Collections.emptyList()
-  List<MarkerTypeEmpty> echo(List<MarkerTypeEmpty> value)
-  throws CollectionsTestServiceException;
+  List<MarkerTypeEmptyList> echo(List<MarkerTypeEmptyList> value)
+      throws CollectionsTestServiceException;
 
   // For Collections.emptyMap()
-  Map<MarkerTypeEmpty, MarkerTypeEmpty> echo(Map<MarkerTypeEmpty,
-      MarkerTypeEmpty> value) throws CollectionsTestServiceException;
+  Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> echo(
+      Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> value) throws CollectionsTestServiceException;
 
   // For Collections.emptySet()
-  Set<MarkerTypeEmpty> echo(Set<MarkerTypeEmpty> value)
-  throws CollectionsTestServiceException;
+  Set<MarkerTypeEmptySet> echo(Set<MarkerTypeEmptySet> value)
+      throws CollectionsTestServiceException;
 
   boolean[] echo(boolean[] value) throws CollectionsTestServiceException;
 
@@ -98,13 +110,17 @@
 
   Float[] echo(Float[] value) throws CollectionsTestServiceException;
 
-  HashMap<String, MarkerTypeHashMap> echo(
-      HashMap<String, MarkerTypeHashMap> value)
+  HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> echo(
+      HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> value)
       throws CollectionsTestServiceException;
 
   HashSet<MarkerTypeHashSet> echo(HashSet<MarkerTypeHashSet> value)
       throws CollectionsTestServiceException;
 
+  IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> echo(
+      IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> value)
+      throws CollectionsTestServiceException;
+
   int[] echo(int[] value) throws CollectionsTestServiceException;
 
   Integer[] echo(Integer[] value) throws CollectionsTestServiceException;
@@ -112,14 +128,17 @@
   java.sql.Date[] echo(java.sql.Date[] value)
       throws CollectionsTestServiceException;
 
-  LinkedHashMap<String, MarkerTypeLinkedHashMap> echo(
-      LinkedHashMap<String, MarkerTypeLinkedHashMap> value)
+  LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> echo(
+      LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> value)
       throws CollectionsTestServiceException;
 
   LinkedHashSet<MarkerTypeLinkedHashSet> echo(
       LinkedHashSet<MarkerTypeLinkedHashSet> value)
       throws CollectionsTestServiceException;
 
+  LinkedList<MarkerTypeLinkedList> echo(LinkedList<MarkerTypeLinkedList> value)
+      throws CollectionsTestServiceException;
+
   long[] echo(long[] value) throws CollectionsTestServiceException;
 
   Long[] echo(Long[] value) throws CollectionsTestServiceException;
@@ -153,6 +172,10 @@
       List<MarkerTypeArraysAsList> value)
       throws CollectionsTestServiceException;
 
+  IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> echoEnumKey(
+      IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> value)
+      throws CollectionsTestServiceException;
+
   // For Collections.singletonList()
   List<MarkerTypeSingleton> echoSingletonList(List<MarkerTypeSingleton> 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 10732bd..226d03f 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 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -17,11 +17,20 @@
 
 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.MarkerTypeEmpty;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
 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.MarkerTypeIdentityHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapValue;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedList;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
@@ -33,8 +42,10 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -43,23 +54,23 @@
 import java.util.Vector;
 
 /**
- * TODO: document me.
+ * The Remote Service Async class for GWT RPC Collections testing.
  */
 public interface CollectionsTestServiceAsync {
   void echo(ArrayList<MarkerTypeArrayList> value,
       AsyncCallback<ArrayList<MarkerTypeArrayList>> callback);
 
   // For Collections.emptyList()
-  void echo(List<MarkerTypeEmpty> value,
-      AsyncCallback<List<MarkerTypeEmpty>> callback);
+  void echo(List<MarkerTypeEmptyList> value,
+      AsyncCallback<List<MarkerTypeEmptyList>> callback);
 
   // For Collections.emptyMap()
-  void echo(Map<MarkerTypeEmpty, MarkerTypeEmpty> value,
-      AsyncCallback<Map<MarkerTypeEmpty, MarkerTypeEmpty>> callback);
+  void echo(Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> value,
+      AsyncCallback<Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue>> callback);
 
   // For Collections.emptySet()
-  void echo(Set<MarkerTypeEmpty> value,
-      AsyncCallback<Set<MarkerTypeEmpty>> callback);
+  void echo(Set<MarkerTypeEmptySet> value,
+      AsyncCallback<Set<MarkerTypeEmptySet>> callback);
 
   void echo(boolean[] value, AsyncCallback<boolean[]> callback);
 
@@ -85,24 +96,30 @@
 
   void echo(Float[] value, AsyncCallback<Float[]> callback);
 
-  void echo(HashMap<String, MarkerTypeHashMap> value,
-      AsyncCallback<HashMap<String, MarkerTypeHashMap>> callback);
+  void echo(HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> value,
+      AsyncCallback<HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>> callback);
 
   void echo(HashSet<MarkerTypeHashSet> value,
       AsyncCallback<HashSet<MarkerTypeHashSet>> callback);
 
+  void echo(IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> value,
+      AsyncCallback<IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>> 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(LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> value,
+      AsyncCallback<LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>> callback);
 
   void echo(LinkedHashSet<MarkerTypeLinkedHashSet> value,
       AsyncCallback<LinkedHashSet<MarkerTypeLinkedHashSet>> callback);
 
+  void echo(LinkedList<MarkerTypeLinkedList> value,
+      AsyncCallback<LinkedList<MarkerTypeLinkedList>> callback);
+
   void echo(long[] value, AsyncCallback<long[]> callback);
 
   void echo(Long[] value, AsyncCallback<Long[]> callback);
@@ -134,6 +151,9 @@
   void echoArraysAsList(List<MarkerTypeArraysAsList> value,
       AsyncCallback<List<MarkerTypeArraysAsList>> callback);
 
+  void echoEnumKey(IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> value,
+      AsyncCallback<IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue>> callback);
+
   // For Collections.singletonList()
   void echoSingletonList(List<MarkerTypeSingleton> value,
       AsyncCallback<List<MarkerTypeSingleton>> callback);
diff --git a/user/test/com/google/gwt/user/client/rpc/ExceptionsTest.java b/user/test/com/google/gwt/user/client/rpc/ExceptionsTest.java
new file mode 100644
index 0000000..600b5c4
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/ExceptionsTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.rpc;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.UmbrellaException;
+
+/**
+ * Tests serialization of various GWT Exception classes for RPC.
+ */
+public class ExceptionsTest extends RpcTestBase {
+
+  private ExceptionsTestServiceAsync exceptionsTestService;
+
+  public void testUmbrellaException() {
+    ExceptionsTestServiceAsync service = getServiceAsync();
+    delayTestFinishForRpc();
+    final UmbrellaException expected = TestSetFactory.createUmbrellaException();
+    service.echo(expected,
+        new AsyncCallback<UmbrellaException>() {
+          public void onFailure(Throwable caught) {
+            TestSetValidator.rethrowException(caught);
+          }
+
+          public void onSuccess(UmbrellaException result) {
+            assertNotNull(result);
+            assertTrue(TestSetValidator.isValid(expected, result));
+            finishTest();
+          }
+        });
+  }
+
+  private ExceptionsTestServiceAsync getServiceAsync() {
+    if (exceptionsTestService == null) {
+      exceptionsTestService =
+          (ExceptionsTestServiceAsync) GWT.create(ExceptionsTestService.class);
+    }
+    return exceptionsTestService;
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/ExceptionsTestService.java b/user/test/com/google/gwt/user/client/rpc/ExceptionsTestService.java
new file mode 100644
index 0000000..fc258d7
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/ExceptionsTestService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.rpc;
+
+import com.google.gwt.event.shared.UmbrellaException;
+
+/**
+ * Remote Service for testing the serialization of GWT Exception classes.
+ */
+@RemoteServiceRelativePath("exceptions")
+public interface ExceptionsTestService extends RemoteService {
+
+  /**
+   * Exception specific to testing of GWT exception serialization.
+   */
+  final class ExceptionsTestServiceException extends Exception {
+    public ExceptionsTestServiceException() {
+    }
+
+    public ExceptionsTestServiceException(String msg) {
+      super(msg);
+    }
+  }
+
+  UmbrellaException echo(UmbrellaException exception)
+      throws ExceptionsTestServiceException;
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/ExceptionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/ExceptionsTestServiceAsync.java
new file mode 100644
index 0000000..a19197d
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/rpc/ExceptionsTestServiceAsync.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.rpc;
+
+import com.google.gwt.event.shared.UmbrellaException;
+
+/**
+ * Async remote service class for testing GWT Exception serialization.
+ */
+public interface ExceptionsTestServiceAsync {
+  void echo(UmbrellaException exception, AsyncCallback<UmbrellaException> callback);
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
index af3d296..ff5e331 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -24,7 +24,7 @@
 import com.google.gwt.user.client.rpc.InheritanceTestSetFactory.SerializableSubclass;
 
 /**
- * TODO: document me.
+ * Tests RPC serialization of classes without custom serializers.
  */
 public class InheritanceTest extends RpcTestBase {
 
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 4831bfd..cdb4ea0 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.user.client.rpc;
 
+import com.google.gwt.event.shared.UmbrellaException;
+
 import java.io.Serializable;
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -24,8 +26,10 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -107,8 +111,38 @@
    * A single-use marker type to independently check type parameter exposure in
    * various empty collections.
    */
-  public static final class MarkerTypeEmpty extends MarkerBase {
-    MarkerTypeEmpty() {
+  public static final class MarkerTypeEmptyKey extends MarkerBase {
+    MarkerTypeEmptyKey() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various empty collections.
+   */
+  public static final class MarkerTypeEmptyList extends MarkerBase {
+    MarkerTypeEmptyList() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various empty collections.
+   */
+  public static final class MarkerTypeEmptySet extends MarkerBase {
+    MarkerTypeEmptySet() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various empty collections.
+   */
+  public static final class MarkerTypeEmptyValue extends MarkerBase {
+    MarkerTypeEmptyValue() {
       super(null);
     }
   }
@@ -125,13 +159,13 @@
    * A single-use marker type to independently check type parameter exposure in
    * various collections.
    */
-  public static final class MarkerTypeHashMap extends MarkerBase {
+  public static final class MarkerTypeHashMapKey extends MarkerBase {
 
-    public MarkerTypeHashMap(String value) {
+    public MarkerTypeHashMapKey(String value) {
       super(value);
     }
 
-    MarkerTypeHashMap() {
+    MarkerTypeHashMapKey() {
       super(null);
     }
   }
@@ -140,6 +174,20 @@
    * A single-use marker type to independently check type parameter exposure in
    * various collections.
    */
+  public static final class MarkerTypeHashMapValue extends MarkerBase {
+
+    public MarkerTypeHashMapValue(String value) {
+      super(value);
+    }
+
+    MarkerTypeHashMapValue() {
+      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) {
@@ -155,13 +203,58 @@
    * A single-use marker type to independently check type parameter exposure in
    * various collections.
    */
-  public static final class MarkerTypeLinkedHashMap extends MarkerBase {
+  public static final class MarkerTypeIdentityHashMapKey extends MarkerBase {
 
-    public MarkerTypeLinkedHashMap(String value) {
+    public MarkerTypeIdentityHashMapKey(String value) {
       super(value);
     }
 
-    MarkerTypeLinkedHashMap() {
+    MarkerTypeIdentityHashMapKey() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeIdentityHashMapValue extends MarkerBase {
+
+    public MarkerTypeIdentityHashMapValue(String value) {
+      super(value);
+    }
+
+    MarkerTypeIdentityHashMapValue() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeLinkedHashMapKey extends MarkerBase {
+
+    public MarkerTypeLinkedHashMapKey(String value) {
+      super(value);
+    }
+
+    MarkerTypeLinkedHashMapKey() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeLinkedHashMapValue extends MarkerBase {
+
+    public MarkerTypeLinkedHashMapValue(String value) {
+      super(value);
+    }
+
+    MarkerTypeLinkedHashMapValue() {
       super(null);
     }
   }
@@ -183,6 +276,21 @@
 
   /**
    * A single-use marker type to independently check type parameter exposure in
+   * various collections.
+   */
+  public static final class MarkerTypeLinkedList extends MarkerBase {
+
+    public MarkerTypeLinkedList(String value) {
+      super(value);
+    }
+
+    MarkerTypeLinkedList() {
+      super(null);
+    }
+  }
+
+  /**
+   * A single-use marker type to independently check type parameter exposure in
    * singleton collections.
    */
   public static final class MarkerTypeSingleton extends MarkerBase {
@@ -423,15 +531,15 @@
         new Double(Double.MAX_VALUE), new Double(Double.MIN_VALUE)};
   }
 
-  public static List<MarkerTypeEmpty> createEmptyList() {
+  public static List<MarkerTypeEmptyList> createEmptyList() {
     return java.util.Collections.emptyList();
   }
 
-  public static Map<MarkerTypeEmpty, MarkerTypeEmpty> createEmptyMap() {
+  public static Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> createEmptyMap() {
     return java.util.Collections.emptyMap();
   }
 
-  public static Set<MarkerTypeEmpty> createEmptySet() {
+  public static Set<MarkerTypeEmptySet> createEmptySet() {
     return java.util.Collections.emptySet();
   }
 
@@ -446,13 +554,14 @@
         new Float(Float.MAX_VALUE), new Float(Float.MIN_VALUE)};
   }
 
-  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"));
+  public static HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> createHashMap() {
+    HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> map =
+        new HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>();
+    map.put(new MarkerTypeHashMapKey("foo"), new MarkerTypeHashMapValue("foo"));
+    map.put(new MarkerTypeHashMapKey("bar"), new MarkerTypeHashMapValue("bar"));
+    map.put(new MarkerTypeHashMapKey("baz"), new MarkerTypeHashMapValue("baz"));
+    map.put(new MarkerTypeHashMapKey("bal"), new MarkerTypeHashMapValue("bal"));
+    map.put(new MarkerTypeHashMapKey("w00t"), new MarkerTypeHashMapValue("w00t"));
     return map;
   }
 
@@ -466,19 +575,50 @@
     return set;
   }
 
+  public static IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> createIdentityHashMapEnumKey() {
+    IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> map =
+        new IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue>();
+    /*
+     * An Enum hash map lets us check that references to Enums remain constant
+     * across RPC send-receive cycles.
+     */
+    map.put(MarkerTypeEnum.A, new MarkerTypeIdentityHashMapValue("A"));
+    map.put(MarkerTypeEnum.B, new MarkerTypeIdentityHashMapValue("B"));
+    map.put(MarkerTypeEnum.C, new MarkerTypeIdentityHashMapValue("C"));
+    return map;
+  }
+
+  public static IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> createIdentityHashMap() {
+    IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> map =
+        new IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>();
+    /*
+     * The two distinct instances of the Integer 1 will remain distinct in the
+     * IdentityHashMap because they are not reference equal. They should
+     * serialize such that the two distinct entries remain.
+     */
+    map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo1"));
+    map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo2"));
+    map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo3"));
+    map.put(new MarkerTypeIdentityHashMapKey("bar"), new MarkerTypeIdentityHashMapValue("bar"));
+    map.put(new MarkerTypeIdentityHashMapKey("baz"), new MarkerTypeIdentityHashMapValue("baz"));
+    map.put(new MarkerTypeIdentityHashMapKey("bal"), new MarkerTypeIdentityHashMapValue("bal"));
+    return map;
+  }
+
   public static Integer[] createIntegerArray() {
     return new Integer[] {
         new Integer(Integer.MAX_VALUE), new Integer(Integer.MIN_VALUE),
         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"));
+  public static LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> createLinkedHashMap() {
+    LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> map =
+        new LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>();
+    map.put(new MarkerTypeLinkedHashMapKey("foo"), new MarkerTypeLinkedHashMapValue("foo"));
+    map.put(new MarkerTypeLinkedHashMapKey("bar"), new MarkerTypeLinkedHashMapValue("bar"));
+    map.put(new MarkerTypeLinkedHashMapKey("baz"), new MarkerTypeLinkedHashMapValue("baz"));
+    map.put(new MarkerTypeLinkedHashMapKey("bal"), new MarkerTypeLinkedHashMapValue("bal"));
+    map.put(new MarkerTypeLinkedHashMapKey("w00t"), new MarkerTypeLinkedHashMapValue("w00t"));
     return map;
   }
 
@@ -492,6 +632,16 @@
     return set;
   }
 
+  public static LinkedList<MarkerTypeLinkedList> createLinkedList() {
+    LinkedList<MarkerTypeLinkedList> list = new LinkedList<MarkerTypeLinkedList>();
+    list.add(new MarkerTypeLinkedList("foo"));
+    list.add(new MarkerTypeLinkedList("bar"));
+    list.add(new MarkerTypeLinkedList("baz"));
+    list.add(new MarkerTypeLinkedList("bal"));
+    list.add(new MarkerTypeLinkedList("w00t"));
+    return list;
+  }
+
   public static Long[] createLongArray() {
     long a = 16123432898849345L;
     long b = 78234569989880099L;
@@ -510,14 +660,14 @@
         new Long(a), new Long(b), new Long(c)};
   }
 
-  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"));
+  public static LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> createLRULinkedHashMap() {
+    LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> map =
+        new LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>(100, 1.0f, true);
+    map.put(new MarkerTypeLinkedHashMapKey("foo"), new MarkerTypeLinkedHashMapValue("foo"));
+    map.put(new MarkerTypeLinkedHashMapKey("bar"), new MarkerTypeLinkedHashMapValue("bar"));
+    map.put(new MarkerTypeLinkedHashMapKey("baz"), new MarkerTypeLinkedHashMapValue("baz"));
+    map.put(new MarkerTypeLinkedHashMapKey("bal"), new MarkerTypeLinkedHashMapValue("bal"));
+    map.put(new MarkerTypeLinkedHashMapKey("w00t"), new MarkerTypeLinkedHashMapValue("w00t"));
     return map;
   }
 
@@ -713,4 +863,14 @@
 
     return root;
   }
+
+  public static UmbrellaException createUmbrellaException() {
+    Set<Throwable> causes = new HashSet<Throwable>();
+    UmbrellaException exception = new UmbrellaException(causes);
+    SerializationException e1 = new SerializationException("Test Message 1", exception);
+    SerializationException e2 = new SerializationException("Test Message 2", e1);
+    causes.add(e1);
+    causes.add(e2);
+    return exception;
+  }
 }
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 d65dbf7..5c68518 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -15,7 +15,14 @@
  */
 package com.google.gwt.user.client.rpc;
 
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmpty;
+import com.google.gwt.event.shared.UmbrellaException;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
@@ -33,9 +40,11 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -264,6 +273,34 @@
     return true;
   }
 
+  private static boolean equals(Throwable expected, Throwable actual) {
+    // If one is null, both must be null (or vice-versa)
+    if ((expected == null) != (actual == null)) {
+      return false;
+    }
+    // Only check expected for null, as we know that actual is the same.
+    if (actual == null) {
+      return false;
+    }
+
+    String expectedMessage = expected.getMessage();
+    String actualMessage = actual.getMessage();
+    if (!equalsWithNullCheck(expectedMessage, actualMessage)) {
+        return false;
+    }
+
+    /*
+     * The cause field is not serialized, so we cannot verify it.
+     */
+
+    /*
+     * Stack traces are not comparable because they are automatically filled in when
+     * the exception is instantiated, with the instantiation site's stack trace.
+     */
+    
+    return true;
+  }
+
   public static boolean isValid(ArrayList<?> list) {
     if (list == null) {
       return false;
@@ -277,15 +314,15 @@
     return reference.equals(list);
   }
 
-  public static boolean isValid(List<MarkerTypeEmpty> list) {
+  public static boolean isValid(List<MarkerTypeEmptyList> list) {
     return list != null && list.size() == 0;
   }
 
-  public static boolean isValid(Map<MarkerTypeEmpty, MarkerTypeEmpty> map) {
+  public static boolean isValid(Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> map) {
     return map != null && map.size() == 0;
   }
 
-  public static boolean isValid(Set<MarkerTypeEmpty> set) {
+  public static boolean isValid(Set<MarkerTypeEmptySet> set) {
     return set != null && set.size() == 0;
   }
 
@@ -339,6 +376,87 @@
 
     return true;
   }
+  
+  public static boolean isValidEnumKey(
+      IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> expected,
+      IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> map) {
+    if (map == null) {
+      return false;
+    }
+
+    if (expected.size() != map.size()) {
+      return false;
+    }
+
+    Set<?> entries = expected.entrySet();
+    Iterator<?> entryIter = entries.iterator();
+    while (entryIter.hasNext()) {
+      Entry<?, ?> entry = (Entry<?, ?>) entryIter.next();
+
+      Object value = map.get(entry.getKey());
+
+      if (value != entry.getValue()) {
+        if (value == null || entry.getValue() == null) {
+          return false;
+        }
+
+        if (!map.get(entry.getKey()).equals(entry.getValue())) {
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  public static boolean isValid(
+      IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> expected,
+      IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> map) {
+    if (map == null) {
+      return false;
+    }
+
+    if (expected.size() != map.size()) {
+      return false;
+    }
+    
+    Set<Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>> mapEntries =
+        map.entrySet();
+    Set<Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>> expectedEntries =
+        expected.entrySet();
+
+    /*
+     * An IdentityHashMap uses reference equality for keys. The maps we are
+     * comparing have keys from different sources, so we cannot simply use get
+     * to find one key in the other map. Instead we need to iterate looking for
+     * equality. We do not check for null keys/value; rather, catch them with
+     * NPEs.
+     */
+    Iterator<Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>> expectedIter =
+        expectedEntries.iterator();
+    while (expectedIter.hasNext()) {
+      Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> expectedEntry =
+          expectedIter.next();
+
+      Iterator<Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>> mapIter =
+          mapEntries.iterator();
+      boolean found = false;
+      while (!found && mapIter.hasNext()) {
+        Entry<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> mapEntry =
+            mapIter.next();
+
+        if (mapEntry.getKey().equals(expectedEntry.getKey())
+            && mapEntry.getValue().equals(expectedEntry.getValue())) {
+          found = true;
+        }
+      }
+      if (!found) {
+        return false;
+      }
+    }
+
+    return true;
+  }
 
   public static boolean isValid(LinkedHashMap<?, ?> expected,
       LinkedHashMap<?, ?> map) {
@@ -359,6 +477,16 @@
     return false;
   }
 
+  public static boolean isValid(LinkedList<?> expected, LinkedList<?> actual) {
+    if (actual == null) {
+      return false;
+    }
+
+    Iterator<?> expectedEntries = expected.iterator();
+    Iterator<?> actualEntries = actual.iterator();
+    return equals(expectedEntries, actualEntries);
+  }
+
   public static boolean isValid(SerializablePrivateNoArg actual) {
     if (actual == null) {
       return false;
@@ -429,6 +557,66 @@
     return true;
   }
 
+  public static boolean isValid(UmbrellaException expected, UmbrellaException actual) {
+    if (actual == null) {
+      return false;
+    }
+    
+    /*
+     * Throwable doesn't declare equals.
+     */
+    if (!equals(expected, actual)) {
+      return false;
+    }
+
+    /* Check causes. */
+    Set<Throwable> expectedCauses = expected.getCauses();
+    Set<Throwable> actualCauses = actual.getCauses();
+
+    /* Size. */
+    if (actualCauses.size() != expectedCauses.size()) {
+      return false;
+    }
+    
+    /* Null elements, and make a copy of the actualCauses set */
+    Iterator<Throwable> expectedIter = expectedCauses.iterator();
+    while (expectedIter.hasNext()) {
+      Throwable expectedCause = expectedIter.next();
+      if (expectedCause == null) {
+        return false;
+      }
+    }
+    Iterator<Throwable> actualIter = actualCauses.iterator();
+    while (actualIter.hasNext()) {
+      Throwable actualCause = actualIter.next();
+      if (actualCause == null) {
+        return false;
+      }
+    }
+    
+    /*
+     * The elements themselves. We rely on the fact that the test sets do not
+     * contain duplicates of causes.
+     */
+    expectedIter = expectedCauses.iterator();
+    while (expectedIter.hasNext()) {
+      Throwable expectedCause = expectedIter.next();
+      actualIter = actualCauses.iterator();
+      boolean found = false;
+      while (!found && actualIter.hasNext()) {
+        Throwable actualCause = actualIter.next();
+        if (equals(expectedCause, actualCause)) {
+          found = true;
+        }
+      }
+      if (!found) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+  
   public static boolean isValid(Vector<?> expected, Vector<?> actual) {
     if (actual == null) {
       return false;
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 f0ce23a..3a7e2b6 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2011 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -17,18 +17,27 @@
 
 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.MarkerTypeEmptyKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
 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.MarkerTypeEmpty;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
 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.MarkerTypeIdentityHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapValue;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedList;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
 import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
+import com.google.gwt.user.client.rpc.TestSetValidator;
 
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -37,8 +46,10 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -189,10 +200,10 @@
     return actual;
   }
 
-  public HashMap<String, MarkerTypeHashMap> echo(
-      HashMap<String, MarkerTypeHashMap> actual)
+  public HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> echo(
+      HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> actual)
       throws CollectionsTestServiceException {
-    HashMap<String, MarkerTypeHashMap> expected = TestSetFactory.createHashMap();
+    HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> expected = TestSetFactory.createHashMap();
     if (!TestSetValidator.isValid(expected, actual)) {
       throw new CollectionsTestServiceException("expected: "
           + expected.toString() + " actual: " + actual.toString());
@@ -212,6 +223,18 @@
     return actual;
   }
 
+  public IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> echo(
+      IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> actual)
+      throws CollectionsTestServiceException {
+    IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> expected = TestSetFactory.createIdentityHashMap();
+    if (!TestSetValidator.isValid(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + expected.toString() + " actual: " + actual.toString());
+    }
+
+    return actual;
+  }
+
   public int[] echo(int[] actual) throws CollectionsTestServiceException {
     int[] expected = TestSetFactory.createPrimitiveIntegerArray();
     if (!TestSetValidator.equals(expected, actual)) {
@@ -249,10 +272,10 @@
     return actual;
   }
 
-  public LinkedHashMap<String, MarkerTypeLinkedHashMap> echo(
-      LinkedHashMap<String, MarkerTypeLinkedHashMap> actual)
+  public LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> echo(
+      LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> actual)
       throws CollectionsTestServiceException {
-    LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLinkedHashMap();
+    LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> expected = TestSetFactory.createLinkedHashMap();
     if (!TestSetValidator.isValid(expected, actual)) {
       throw new CollectionsTestServiceException("expected: "
           + expected.toString() + " actual: " + actual.toString());
@@ -271,7 +294,18 @@
     return actual;
   }
 
-  public List<MarkerTypeEmpty> echo(List<MarkerTypeEmpty> list)
+  public LinkedList<MarkerTypeLinkedList> echo(LinkedList<MarkerTypeLinkedList> actual)
+      throws CollectionsTestServiceException {
+    LinkedList<MarkerTypeLinkedList> expected = TestSetFactory.createLinkedList();
+    if (!TestSetValidator.isValid(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + expected.toString() + " actual: " + actual.toString());
+    }
+
+    return actual;
+  }
+
+  public List<MarkerTypeEmptyList> echo(List<MarkerTypeEmptyList> list)
       throws CollectionsTestServiceException {
     if (!TestSetValidator.isValid(list)) {
       throw new CollectionsTestServiceException();
@@ -300,8 +334,8 @@
     return actual;
   }
 
-  public Map<MarkerTypeEmpty, MarkerTypeEmpty> echo(
-      Map<MarkerTypeEmpty, MarkerTypeEmpty> map)
+  public Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> echo(
+      Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> map)
       throws CollectionsTestServiceException {
     if (!TestSetValidator.isValid(map)) {
       throw new CollectionsTestServiceException();
@@ -310,7 +344,7 @@
     return map;
   }
 
-  public Set<MarkerTypeEmpty> echo(Set<MarkerTypeEmpty> set)
+  public Set<MarkerTypeEmptySet> echo(Set<MarkerTypeEmptySet> set)
       throws CollectionsTestServiceException {
     if (!TestSetValidator.isValid(set)) {
       throw new CollectionsTestServiceException();
@@ -430,6 +464,18 @@
     return value;
   }
 
+  public IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> echoEnumKey(
+      IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> actual)
+      throws CollectionsTestServiceException {
+    IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> expected = TestSetFactory.createIdentityHashMapEnumKey();
+    if (!TestSetValidator.isValidEnumKey(expected, actual)) {
+      throw new CollectionsTestServiceException("expected: "
+          + expected.toString() + " actual: " + actual.toString());
+    }
+
+    return actual;
+  }
+
   public List<MarkerTypeSingleton> echoSingletonList(
       List<MarkerTypeSingleton> value) throws CollectionsTestServiceException {
     if (!TestSetValidator.isValidSingletonList(value)) {
diff --git a/user/test/com/google/gwt/user/server/rpc/ExceptionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/ExceptionsTestServiceImpl.java
new file mode 100644
index 0000000..ed8bdd4
--- /dev/null
+++ b/user/test/com/google/gwt/user/server/rpc/ExceptionsTestServiceImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.server.rpc;
+
+import com.google.gwt.event.shared.UmbrellaException;
+import com.google.gwt.user.client.rpc.ExceptionsTestService;
+import com.google.gwt.user.client.rpc.TestSetFactory;
+import com.google.gwt.user.client.rpc.TestSetValidator;
+
+/**
+ * Remote Service Implementation for Exception serialization tests.
+ */
+public class ExceptionsTestServiceImpl extends HybridServiceServlet implements
+    ExceptionsTestService {
+
+  public UmbrellaException echo(UmbrellaException exception)
+      throws ExceptionsTestServiceException {
+    UmbrellaException expected = TestSetFactory.createUmbrellaException();
+    if (!TestSetValidator.isValid(expected, exception)) {
+      throw new ExceptionsTestServiceException();
+    }
+
+    return exception;
+  }
+
+}