Fix for http://code.google.com/p/google-web-toolkit/issues/detail?id=4814
Fixes a bug with deRPC serialization of boolean values. When a boolean value
is read by the client, it's currently interpreted as a number. When it's
serialized again to the server, it becomes a Double object.

This change adds a test to isolate the issue, and a proposed fix. Instead of
requiring the argument to be written as 'false' to the client, it relaxes what
the server accepts as potential boolean values, allowing 0 or 1 as well.

Review by: robertvawter@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8361 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/rpc/server/CommandSerializationUtil.java b/user/src/com/google/gwt/rpc/server/CommandSerializationUtil.java
index c83c00d..9e68812 100644
--- a/user/src/com/google/gwt/rpc/server/CommandSerializationUtil.java
+++ b/user/src/com/google/gwt/rpc/server/CommandSerializationUtil.java
@@ -103,8 +103,20 @@
 
       @Override
       public void set(Object instance, long offset, Object value) {
-        theUnsafe.putBoolean(instance, offset, ((Boolean) value));
+        theUnsafe.putBoolean(instance, offset, toBoolean(value));
       }
+
+      private boolean toBoolean(Object value) {
+        if (value instanceof Number) {
+          return ((Number) value).intValue() != 0;
+        } else if (value instanceof String) {
+          return Boolean.valueOf((String) value);
+        } else {
+          // returns false if the value is null.
+          return Boolean.TRUE.equals(value);
+        }
+      }
+
     },
     BYTE {
       @Override
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 eb4a87c..af3d296 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTest.java
@@ -95,6 +95,33 @@
   }
 
   /**
+   * Tests that a serialized type can be sent again on the wire.
+   */
+  public void testResendJavaSerializableClass() {
+    final InheritanceTestServiceAsync service = getServiceAsync();
+    final InheritanceTestSetFactory.JavaSerializableClass first =
+        new InheritanceTestSetFactory.JavaSerializableClass(3);
+    AsyncCallback<Object> resendCallback = new AsyncCallback<Object>() {
+        private boolean resend = true;
+        public void onFailure(Throwable caught) {
+          TestSetValidator.rethrowException(caught);
+        }
+
+        public void onSuccess(Object result) {
+          assertEquals(first, result);
+          if (resend) {
+            resend = false;
+            service.echo((InheritanceTestSetFactory.JavaSerializableClass) result, this);
+          } else {
+            finishTest();
+          }
+        }
+    };
+    delayTestFinishForRpc();
+    service.echo(first, resendCallback);
+  }
+
+  /**
    * Test that non-static inner classes are not serializable.
    */
   public void testNonStaticInnerClass() {
diff --git a/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
index 19ab5e3..2e11f75 100644
--- a/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/InheritanceTestSetFactory.java
@@ -72,6 +72,23 @@
     public JavaSerializableBaseClass(int field1) {
       this.field1 = field1;
     }
+
+    @Override
+    public int hashCode() {
+      return field1;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (obj == this) {
+        return true;
+      }
+      if (obj == null || obj.getClass() != this.getClass()) {
+        return false;
+      }
+      JavaSerializableBaseClass other = (JavaSerializableBaseClass) obj;
+      return field1 == other.field1;
+    }
   }
 
   /**
@@ -79,6 +96,7 @@
    */
   public static class JavaSerializableClass extends JavaSerializableBaseClass {
     private int field2 = -2;
+    private boolean field3 = true;
 
     public JavaSerializableClass() {
     }
@@ -86,6 +104,23 @@
     public JavaSerializableClass(int field2) {
       this.field2 = field2;
     }
+
+    @Override
+    public int hashCode() {
+      return super.hashCode() << 19 + field2;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (obj == this) {
+        return true;
+      }
+      if (obj == null || obj.getClass() != this.getClass()) {
+        return false;
+      }
+      JavaSerializableClass other = (JavaSerializableClass) obj;
+      return super.equals(other) && field2 == other.field2 && field3 == other.field3;
+    }
   }
 
   /**