Integrate RequestFactory Receiver exception handling fixes into 2.2 branch.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.2@9545 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/requestfactory/server/testing/InProcessRequestTransport.java b/user/src/com/google/gwt/requestfactory/server/testing/InProcessRequestTransport.java
index cf713be..b215b4f 100644
--- a/user/src/com/google/gwt/requestfactory/server/testing/InProcessRequestTransport.java
+++ b/user/src/com/google/gwt/requestfactory/server/testing/InProcessRequestTransport.java
@@ -47,18 +47,20 @@
   }
 
   public void send(String payload, TransportReceiver receiver) {
+    String result;
     try {
       if (DUMP_PAYLOAD) {
         System.out.println(">>> " + payload);
       }
-      String result = processor.process(payload);
+      result = processor.process(payload);
       if (DUMP_PAYLOAD) {
         System.out.println("<<< " + result);
       }
-      receiver.onTransportSuccess(result);
     } catch (RuntimeException e) {
       e.printStackTrace();
       receiver.onTransportFailure(new ServerFailure(e.getMessage()));
+      return;
     }
+    receiver.onTransportSuccess(result);
   }
 }
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
index 3027693..4f7e01d 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
@@ -24,6 +24,7 @@
 import com.google.gwt.autobean.shared.AutoBeanVisitor;
 import com.google.gwt.autobean.shared.Splittable;
 import com.google.gwt.autobean.shared.ValueCodex;
+import com.google.gwt.event.shared.UmbrellaException;
 import com.google.gwt.requestfactory.shared.BaseProxy;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyChange;
@@ -628,14 +629,7 @@
             errors.add(new MyViolation(message));
           }
 
-          reuse();
-          for (AbstractRequest<?> request : new ArrayList<AbstractRequest<?>>(
-              invocations)) {
-            request.onViolation(errors);
-          }
-          if (receiver != null) {
-            receiver.onViolation(errors);
-          }
+          violation(receiver, errors);
           return;
         }
 
@@ -643,37 +637,115 @@
         processReturnOperations(response);
 
         // Send return values
+        Set<Throwable> causes = null;
         for (int i = 0, j = invocations.size(); i < j; i++) {
-          if (response.getStatusCodes().get(i)) {
-            invocations.get(i).onSuccess(response.getInvocationResults().get(i));
-          } else {
-            ServerFailureMessage failure = AutoBeanCodex.decode(
-                MessageFactoryHolder.FACTORY, ServerFailureMessage.class,
-                response.getInvocationResults().get(i)).as();
-            invocations.get(i).onFail(
-                new ServerFailure(failure.getMessage(),
-                    failure.getExceptionType(), failure.getStackTrace(),
-                    failure.isFatal()));
+          try {
+            if (response.getStatusCodes().get(i)) {
+              invocations.get(i).onSuccess(
+                  response.getInvocationResults().get(i));
+            } else {
+              ServerFailureMessage failure = AutoBeanCodex.decode(
+                  MessageFactoryHolder.FACTORY, ServerFailureMessage.class,
+                  response.getInvocationResults().get(i)).as();
+              invocations.get(i).onFail(
+                  new ServerFailure(failure.getMessage(),
+                      failure.getExceptionType(), failure.getStackTrace(),
+                      failure.isFatal()));
+            }
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
           }
         }
 
         if (receiver != null) {
-          receiver.onSuccess(null);
+          try {
+            receiver.onSuccess(null);
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
+          }
         }
         // After success, shut down the context
         editedProxies.clear();
         invocations.clear();
         returnedProxies.clear();
+
+        if (causes != null) {
+          throw new UmbrellaException(causes);
+        }
       }
 
+      /**
+       * Invoke the appropriate {@code onFailure} callbacks, possibly throwing
+       * an {@link UmbrellaException} if one or more callbacks fails.
+       */
       private void fail(Receiver<Void> receiver, ServerFailure failure) {
         reuse();
+        Set<Throwable> causes = null;
         for (AbstractRequest<?> request : new ArrayList<AbstractRequest<?>>(
             invocations)) {
-          request.onFail(failure);
+          try {
+            request.onFail(failure);
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
+          }
         }
         if (receiver != null) {
-          receiver.onFailure(failure);
+          try {
+            receiver.onFailure(failure);
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
+          }
+        }
+
+        if (causes != null) {
+          throw new UmbrellaException(causes);
+        }
+      }
+
+      /**
+       * Invoke the appropriate {@code onViolation} callbacks, possibly throwing
+       * an {@link UmbrellaException} if one or more callbacks fails.
+       */
+      private void violation(final Receiver<Void> receiver,
+          Set<Violation> errors) {
+        reuse();
+        Set<Throwable> causes = null;
+        for (AbstractRequest<?> request : new ArrayList<AbstractRequest<?>>(
+            invocations)) {
+          try {
+            request.onViolation(errors);
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
+          }
+        }
+        if (receiver != null) {
+          try {
+            receiver.onViolation(errors);
+          } catch (Throwable t) {
+            if (causes == null) {
+              causes = new HashSet<Throwable>();
+            }
+            causes.add(t);
+          }
+        }
+
+        if (causes != null) {
+          throw new UmbrellaException(causes);
         }
       }
     });
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
index 85d7956..b203b56 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
@@ -20,6 +20,7 @@
 import com.google.gwt.requestfactory.server.ComplexKeysJreTest;
 import com.google.gwt.requestfactory.server.FindServiceJreTest;
 import com.google.gwt.requestfactory.server.LocatorJreTest;
+import com.google.gwt.requestfactory.server.RequestFactoryExceptionPropagationJreTest;
 import com.google.gwt.requestfactory.server.RequestFactoryInterfaceValidatorTest;
 import com.google.gwt.requestfactory.server.RequestFactoryJreTest;
 import com.google.gwt.requestfactory.server.RequestFactoryUnicodeEscapingJreTest;
@@ -39,11 +40,12 @@
     suite.addTestSuite(ComplexKeysJreTest.class);
     suite.addTestSuite(FindServiceJreTest.class);
     suite.addTestSuite(LocatorJreTest.class);
-    suite.addTestSuite(RequestFactoryJreTest.class);
-    suite.addTestSuite(SimpleEntityProxyIdTest.class);
+    suite.addTestSuite(RequestFactoryExceptionPropagationJreTest.class);
     suite.addTestSuite(RequestFactoryInterfaceValidatorTest.class);
+    suite.addTestSuite(RequestFactoryJreTest.class);
     suite.addTestSuite(RequestFactoryModelTest.class);
     suite.addTestSuite(RequestFactoryUnicodeEscapingJreTest.class);
+    suite.addTestSuite(SimpleEntityProxyIdTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
index 72cad85..6e8311b 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
@@ -18,6 +18,7 @@
 import com.google.gwt.junit.tools.GWTTestSuite;
 import com.google.gwt.requestfactory.client.FindServiceTest;
 import com.google.gwt.requestfactory.client.RequestFactoryExceptionHandlerTest;
+import com.google.gwt.requestfactory.client.RequestFactoryExceptionPropagationTest;
 import com.google.gwt.requestfactory.client.RequestFactoryPolymorphicTest;
 import com.google.gwt.requestfactory.client.RequestFactoryTest;
 import com.google.gwt.requestfactory.client.RequestFactoryUnicodeEscapingTest;
@@ -42,6 +43,7 @@
     suite.addTestSuite(LocatorTest.class);
     suite.addTestSuite(RequestFactoryTest.class);
     suite.addTestSuite(RequestFactoryExceptionHandlerTest.class);
+    suite.addTestSuite(RequestFactoryExceptionPropagationTest.class);
     suite.addTestSuite(RequestFactoryPolymorphicTest.class);
     suite.addTestSuite(RequestFactoryUnicodeEscapingTest.class);
     return suite;
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionPropagationTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionPropagationTest.java
new file mode 100644
index 0000000..dbeb250
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionPropagationTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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.requestfactory.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.UmbrellaException;
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.RequestContext;
+import com.google.gwt.requestfactory.shared.ServerFailure;
+import com.google.gwt.requestfactory.shared.SimpleFooProxy;
+import com.google.gwt.requestfactory.shared.SimpleFooRequest;
+import com.google.gwt.requestfactory.shared.Violation;
+
+import java.util.Set;
+
+/**
+ * Tests that an exception thrown by a {@link Receiver} does not prevent other
+ * {@link Receiver}s from being called.
+ */
+public class RequestFactoryExceptionPropagationTest extends
+    RequestFactoryTestBase {
+  /*
+   * DO NOT USE finishTest(). Instead, call finishTestAndReset();
+   */
+
+  private class CountingReceiver extends Receiver<Object> {
+    int failureCallCount;
+    int successCallCount;
+    int violationCallCount;
+
+    public void assertCounts(int expectedFailureCallCount,
+        int expectedSuccessCallCount, int expectedViolationCallCount) {
+      assertEquals(expectedFailureCallCount, failureCallCount);
+      assertEquals(expectedSuccessCallCount, successCallCount);
+      assertEquals(expectedViolationCallCount, violationCallCount);
+    }
+
+    @Override
+    public void onFailure(ServerFailure error) {
+      failureCallCount++;
+    }
+
+    @Override
+    public void onSuccess(Object response) {
+      successCallCount++;
+    }
+
+    @Override
+    public void onViolation(Set<Violation> errors) {
+      violationCallCount++;
+    }
+  }
+
+  private class ThrowingReceiver<T> extends Receiver<T> {
+    private final RuntimeException e;
+
+    public ThrowingReceiver(RuntimeException e) {
+      this.e = e;
+    }
+
+    @Override
+    public void onFailure(ServerFailure error) {
+      throw e;
+    }
+
+    @Override
+    public void onSuccess(T response) {
+      throw e;
+    }
+
+    @Override
+    public void onViolation(Set<Violation> errors) {
+      throw e;
+    }
+  }
+
+  private static final int DELAY_TEST_FINISH = 10 * 1000;
+
+  GWT.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.requestfactory.RequestFactorySuite";
+  }
+
+  @Override
+  public void gwtSetUp() {
+    super.gwtSetUp();
+
+    defaultUncaughtExceptionHandler = GWT.getUncaughtExceptionHandler();
+  }
+
+  /**
+   * Test mixed invocation failure and success. One receiver will throw from
+   * onSuccess and another from onFailure. Other receivers onSuccess and
+   * onFailure will corectly be called.
+   */
+  public void testMixedSuccessAndFailureThrow() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final RuntimeException exception1 = new RuntimeException("first exception");
+    final RuntimeException exception2 = new RuntimeException("second exception");
+    final CountingReceiver count = new CountingReceiver();
+
+    SimpleFooRequest context = req.simpleFooRequest();
+    // 42 is the crash causing magic number for a runtime exception
+    context.pleaseCrash(42).to(count);
+    context.returnNullString().to(new ThrowingReceiver<String>(exception1));
+    context.returnNullString().to(count);
+
+    fireContextAndCatch(context, new ThrowingReceiver<Void>(exception2),
+        new GWT.UncaughtExceptionHandler() {
+          public void onUncaughtException(Throwable e) {
+            if (e instanceof UmbrellaException) {
+              count.assertCounts(1, 1, 0);
+
+              Set<Throwable> causes = ((UmbrellaException) e).getCauses();
+              assertEquals(2, causes.size());
+              assertTrue(causes.contains(exception1));
+              assertTrue(causes.contains(exception2));
+
+              finishTestAndReset();
+            } else {
+              defaultUncaughtExceptionHandler.onUncaughtException(e);
+            }
+          }
+        });
+  }
+
+  /**
+   * Test invocation failure. Other invocations' onSuccess should correctly be
+   * called.
+   */
+  public void testOnFailureThrow() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final RuntimeException exception1 = new RuntimeException("first exception");
+    final RuntimeException exception2 = new RuntimeException("second exception");
+    final CountingReceiver count = new CountingReceiver();
+
+    SimpleFooRequest context = req.simpleFooRequest();
+    context.returnNullString().to(count);
+    // 42 is the crash causing magic number for a runtime exception
+    context.pleaseCrash(42).to(new ThrowingReceiver<Void>(exception1));
+    context.returnNullString().to(count);
+
+    fireContextAndCatch(context, new ThrowingReceiver<Void>(exception2),
+        new GWT.UncaughtExceptionHandler() {
+          public void onUncaughtException(Throwable e) {
+            if (e instanceof UmbrellaException) {
+              count.assertCounts(0, 2, 0);
+
+              Set<Throwable> causes = ((UmbrellaException) e).getCauses();
+              assertEquals(2, causes.size());
+              assertTrue(causes.contains(exception1));
+              assertTrue(causes.contains(exception2));
+
+              finishTestAndReset();
+            } else {
+              defaultUncaughtExceptionHandler.onUncaughtException(e);
+            }
+          }
+        });
+  }
+
+  /**
+   * Test global failure. All receivers will have their onFailure called, and
+   * some of them will throw.
+   */
+  public void testOnGlobalFailureThrow() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final RuntimeException exception1 = new RuntimeException("first exception");
+    final RuntimeException exception2 = new RuntimeException("second exception");
+    final CountingReceiver count = new CountingReceiver();
+
+    SimpleFooRequest context = req.simpleFooRequest();
+    SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
+
+    context.returnNullString().to(count);
+    context.persist().using(newFoo).to(new ThrowingReceiver<Void>(exception1));
+    context.returnNullString().to(count);
+
+    final SimpleFooProxy mutableFoo = context.edit(newFoo);
+    // 42 is the crash causing magic number for a runtime exception
+    mutableFoo.setPleaseCrash(42);
+
+    fireContextAndCatch(context, new ThrowingReceiver<Void>(exception2),
+        new GWT.UncaughtExceptionHandler() {
+          public void onUncaughtException(Throwable e) {
+            if (e instanceof UmbrellaException) {
+              count.assertCounts(2, 0, 0);
+
+              Set<Throwable> causes = ((UmbrellaException) e).getCauses();
+              assertEquals(2, causes.size());
+              assertTrue(causes.contains(exception1));
+              assertTrue(causes.contains(exception2));
+
+              finishTestAndReset();
+            } else {
+              defaultUncaughtExceptionHandler.onUncaughtException(e);
+            }
+          }
+        });
+  }
+
+  /**
+   * All receivers will have their onSuccess called, and some of them will
+   * throw.
+   */
+  public void testOnSuccessThrow() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final RuntimeException exception1 = new RuntimeException("first exception");
+    final RuntimeException exception2 = new RuntimeException("second exception");
+    final CountingReceiver count = new CountingReceiver();
+
+    SimpleFooRequest context = req.simpleFooRequest();
+    context.returnNullString().to(count);
+    context.returnNullString().to(new ThrowingReceiver<String>(exception1));
+    context.returnNullString().to(count);
+
+    fireContextAndCatch(context, new ThrowingReceiver<Void>(exception2),
+        new GWT.UncaughtExceptionHandler() {
+          public void onUncaughtException(Throwable e) {
+            if (e instanceof UmbrellaException) {
+              count.assertCounts(0, 2, 0);
+
+              Set<Throwable> causes = ((UmbrellaException) e).getCauses();
+              assertEquals(2, causes.size());
+              assertTrue(causes.contains(exception1));
+              assertTrue(causes.contains(exception2));
+
+              finishTestAndReset();
+            } else {
+              defaultUncaughtExceptionHandler.onUncaughtException(e);
+            }
+          }
+        });
+  }
+
+  /**
+   * Test violations. All receivers will have their onViolation called, and some
+   * of them will throw.
+   */
+  public void testOnViolationThrow() {
+    delayTestFinish(DELAY_TEST_FINISH);
+
+    final RuntimeException exception1 = new RuntimeException("first exception");
+    final RuntimeException exception2 = new RuntimeException("second exception");
+    final CountingReceiver count = new CountingReceiver();
+
+    SimpleFooRequest context = req.simpleFooRequest();
+    SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
+    newFoo.setUserName("a"); // too short
+
+    context.returnNullString().to(count);
+    context.persist().using(newFoo).to(new ThrowingReceiver<Void>(exception1));
+    context.returnNullString().to(count);
+
+    fireContextAndCatch(context, new ThrowingReceiver<Void>(exception2),
+        new GWT.UncaughtExceptionHandler() {
+          public void onUncaughtException(Throwable e) {
+            if (e instanceof UmbrellaException) {
+              count.assertCounts(0, 0, 2);
+
+              Set<Throwable> causes = ((UmbrellaException) e).getCauses();
+              assertEquals(2, causes.size());
+              assertTrue(causes.contains(exception1));
+              assertTrue(causes.contains(exception2));
+
+              finishTestAndReset();
+            } else {
+              defaultUncaughtExceptionHandler.onUncaughtException(e);
+            }
+          }
+        });
+  }
+
+  protected void fireContextAndCatch(RequestContext context,
+      Receiver<Void> receiver, GWT.UncaughtExceptionHandler exceptionHandler) {
+    GWT.setUncaughtExceptionHandler(exceptionHandler);
+
+    if (receiver == null) {
+      context.fire();
+    } else {
+      context.fire(receiver);
+    }
+  }
+
+  @Override
+  protected void gwtTearDown() throws Exception {
+    GWT.setUncaughtExceptionHandler(defaultUncaughtExceptionHandler);
+  }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionPropagationJreTest.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionPropagationJreTest.java
new file mode 100644
index 0000000..49b5652
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionPropagationJreTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.requestfactory.server;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.requestfactory.client.RequestFactoryExceptionPropagationTest;
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.RequestContext;
+import com.google.gwt.requestfactory.shared.SimpleRequestFactory;
+
+/**
+ * JRE version of {@link RequestFactoryExceptionPropagationTest}.
+ */
+public class RequestFactoryExceptionPropagationJreTest extends
+    RequestFactoryExceptionPropagationTest {
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  @Override
+  protected SimpleRequestFactory createFactory() {
+    return RequestFactoryJreTest.createInProcess(SimpleRequestFactory.class);
+  }
+  
+  @Override
+  protected void fireContextAndCatch(RequestContext context,
+      Receiver<Void> receiver, GWT.UncaughtExceptionHandler exceptionHandler) {
+    try {
+      if (receiver == null) {
+        context.fire();
+      } else {
+        context.fire(receiver);
+      }
+    } catch (Throwable e) {
+      exceptionHandler.onUncaughtException(e);
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index be2632b..dad490c 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -170,6 +170,16 @@
     return foo;
   }
 
+  public static void pleaseCrash(Integer crashIf42or43) throws Exception {
+    if (crashIf42or43 == 42) {
+      throw new UnsupportedOperationException(
+          "THIS EXCEPTION IS EXPECTED BY A TEST");
+    }
+    if (crashIf42or43 == 43) {
+      throw new Exception("THIS EXCEPTION IS EXPECTED BY A TEST");
+    }
+  }
+
   /**
    * Check client-side upcasting to BigDecimal and return a list of BigDecimals
    * that should be upcast.
@@ -754,13 +764,7 @@
   }
 
   public void setPleaseCrash(Integer crashIf42or43) throws Exception {
-    if (crashIf42or43 == 42) {
-      throw new UnsupportedOperationException(
-          "THIS EXCEPTION IS EXPECTED BY A TEST");
-    }
-    if (crashIf42or43 == 43) {
-      throw new Exception("THIS EXCEPTION IS EXPECTED BY A TEST");
-    }
+    pleaseCrash(crashIf42or43);
     pleaseCrash = crashIf42or43;
   }
 
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index a27ad31..8fcc205 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -50,7 +50,7 @@
   Request<Set<Integer>> getNumberSet();
 
   Request<SimpleFooProxy> getSimpleFooWithNullVersion();
-  
+
   Request<SimpleFooProxy> getSimpleFooWithSubPropertyCollection();
 
   Request<SimpleFooProxy> getTripletReference();
@@ -65,10 +65,12 @@
 
   InstanceRequest<SimpleFooProxy, SimpleFooProxy> persistCascadingAndReturnSelf();
 
-  Request<List<BigInteger>> processBigIntegerList(List<BigInteger> values);
+  Request<Void> pleaseCrash(Integer crashIf42or43);
 
   Request<List<BigDecimal>> processBigDecimalList(List<BigDecimal> values);
 
+  Request<List<BigInteger>> processBigIntegerList(List<BigInteger> values);
+
   Request<Boolean> processBooleanList(List<Boolean> values);
 
   Request<List<Date>> processDateList(List<Date> values);