In other words, serialization and deserialization of a long *field*
that is very large (it does not happen to long values that are not
fields) results in lower bit errors (!);
Simplified test case demonstrating the bug:
public class BigNumber implements IsSerializable {
private long number;
public BigNumber() {
number = Long.MAX_VALUE - 5000435;
}
public void print() {
System.out.println(new Long(number).toString());
}
}
/* Server Code */
public BigNumber getBigNumber() {
BigNumber number = new BigNumber();
System.out.println("BigNumber on the server:");
number.print();
return number;
}
/* Client Callback Code */
public void onSuccess(Object result) {
BigNumber number = (BigNumber)result;
System.out.println("BigNumber on the client:");
}
It is expected that it would print the same value (9223372036849775372)
on both client and server, right? But here's the console output:
BigNumber on the server:
9223372036849775372
BigNumber on the client:
9223372036849775636
Notice that the 372 has been transmuted to a 636.
Note that if I return a Long directly instead of a BigNumber,
everything works correctly:
BigNumber on the server:
9223372036849775372
BigNumber on the client:
9223372036849775372
I should add the following clues:
1) The difference between the values is typically quite small (less
than 1000)
2) The difference between the values is consistent between executions
(...372 in results in ...636 out every time)
3) The difference between the values does not change smoothly w/
changing initial long fields (...372 might result in ...636, but ...371
might result in ...239)
4) Sometimes the value is smaller than it should be on the client, and
sometimes it is larger
6) The problem doesn't occur if BigNumber is set to MAX_INT
Some actual values (left is what it was on the server, right is
client):
180000399 -> 180000399
2147873140 -> 2147873140 (this is larger than Integer.MAX_VALUE)
9223372036849775371 -> 9223372036849775616
9223372036849775372 -> 9223372036849775616
9223372036849775369 -> 9223372036849775616
9223372036849775368 -> 9223372036849775616 (notice these all map to the
same)
9223372036854262348 -> 9223372036854262784 (but these don't)
9223372036854275348 -> 9223372036854275072
I remember a post from Scott Blum saying that there is no native long
support in javascript, so GWT simulates this with a double - and that
causes the problem. So longs are really not advisable now. As a matter
of fact, this has also the side effect (from my own poor experience)
that the Date class doesn't always store accurate dates over
serialisation (I suspect the internal representation of dates is a long
notation).
If it is 'only' for IDs try writing your own wrapper class or opt for
Strings. If you have to do maths on client side - well, tough luck :(
G.