2. Big Number Implementations
Overview
Number serialization with the standard AMF3 protocol suffers from a lack of precision and support: Java long (64 bits integers), BigInteger and BigDecimal types are converted to ActionScript3 Number or String (see "Converting data from Java to ActionScript"). These conversions lead to either approximation (significant bits may be lost) or uselessness (you can't do any arithmetic operation with strings and you can't control the way their string representations are produced).
Because GraniteDS doesn't allow string to number or number to string conversions (see 8. Type Conversions (Java ~ ActionScript3)), BigInteger and BigDecimal, like long types, are both converted to Number by default, with even more potential approximations.
Starting with the release 2.2, GraniteDS offers ActionScript3 implementations for Long, BigInteger and BigDecimal, and features a serialization mechanism that preserves the exact value of each type (see API documentation here).
Working with Long, BigInteger or BigDecimal AS3 Types
The GraniteDS Long class let you do calculation with 64 bits signed integers. All arithmetic operations are provided, as well as bitwise, bit shift and comparison operator equivalents:
import org.granite.math.Long; var a:Long = new Long("9223372036854775807"); // or 0x7fffffffffffffff (max long value) trace(a); // "9223372036854775807" trace(a.toHexString()); // "7fffffffffffffff" a = a.subtract(7); trace(a); // "9223372036854775800" trace(a.toHexString()); // "7ffffffffffffff8" a = a.rightShift(4); // or a.divide(16) trace(a); // "576460752303423487" trace(a.toHexString()); // "7ffffffffffffff" // etc. // Wrong values with Numbers: var b:Number = new Number("9223372036854775807"); // max long value trace(b); // "9223372036854776000" (truncated value)...
As you already have noticed from the above code, Long instances (as well as BigInteger and BigDecimal instances) are immutable: a.multiply(2) won't change the value of a, unless if you save the returned value of the method into the variable a (ie: a = a.multiply(2)).
The BigInteger class, as its Java equivalent, represent an immutable arbitrary-precision integer. It provides analogues to all of ActionScript3's primitive integer operators (+, -, *, /), as well as comparison operators.
import org.granite.math.BigInteger; var a:BigInteger = new BigInteger("9223372036854775807"); // max long value a = a.add(1); trace(a); // "9223372036854775808" a = a.multiply(1000000); trace(a); // "9223372036854775808000000" // etc.
With the BigInteger class, you cannot face the risk of an overflow due to the limited storage of a standard numeric type: a BigInteger value can be arbitrary big and its value is only limited by the Flash VM memory.
The BigDecimal class, as its Java equivalent, represent an immutable, arbitrary-precision signed decimal number. It provides operations for arithmetic, scale manipulation, rounding, comparison and format conversion.
import org.granite.math.BigDecimal; import org.granite.math.RoundingMode; var a:BigDecimal = new BigDecimal("1"); // or BigDecimal.ONE a = a.divide(3, 2, RoundingMode.DOWN); trace(a); // "0.33" // etc.
With the BigDecimal class, you can control precisely the scale and the rounding behavior of a division. The above code means: divide 1 by 3, with 2 digits to the right of the decimal point left in the result and apply a down rounding mode (truncate all extra digits). Like BigInteger instances, BigDecimal instances have no precision limitation other than the Flash VM memory.
Note: arithmetic binary methods are more versatile than their Java analogues. You may pass not only BigDecimal instances as parameters to add, subtract, multiply and divide, but also int, Number or String literals. They will be automatically converted to BigDecimal instances and that's why a.add(3) is legal, as well as a.add("3") and a.add(new BigDecimal("3"). This is also true for the Long and BigInteger types.
See the API documentation for more informations.
Serializing Long, BigInteger or BigDecimal
As said above, without any specific configuration, long, Long, BigInteger or BigDecimal Java types are converted to AS3 Number's (and vice-versa). To enable their serializations into their ActionScript3 equivalents, you must enable specific externalizers in your granite-config.xml file.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/2.0.0/granite-config.dtd"> <granite-config> <externalizers> <externalizer type="org.granite.messaging.amf.io.util.externalizer.LongExternalizer"> <include instance-of="java.lang.Long"/> </externalizer> <externalizer type="org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer"> <include instance-of="java.math.BigInteger"/> </externalizer> <externalizer type="org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer"> <include instance-of="java.math.BigDecimal"/> </externalizer> </externalizers> <granite-config>
You may of course enable only the externalizers you need, instead of configuring all of them.
With this configuration, you will be able to receive and send big numbers without potential lose of precision. Suppose you have a Java service that returns and receives BigDecimal values:
import java.math.BigDecimal; public class TestBigDecimal { public BigDecimal returnBigValue() { return new BigDecimal("10000000000000000000000000000.001"); } public void receiveBigValue(BigDecimal value) { // do something with the value. } }
Within your Flex code, provided that the BigDecimalExternalizer is configured, you could use this kind of code:
import org.granite.math.BigDecimal; private var testBigDecimalService:RemoteObject = null; private var value:BigDecimal = null; ... protected function onReturnBigValueResult(event:ResultEvent):void { value = event.result as BigDecimal; } ... protected function sendBigValue():void { testBigDecimalService.receiveBigValue(new BigDecimal("0.3333")); }
The same kind of code will work with long, Long and BigInteger types as well.
Integration with Code Generation Tools
Beside calling methods that return or receive big numbers, you may have Java bean or entity properties that use long, Long, BigInteger or BigDecimal types. The standard GraniteDS code generation tools (see 3. Gas3 Code Generator) follow the standard serialization mechanism (ie: converting long and big number types to AS3 numbers) and generates Number typed variables for Java long and big number types.
In order to tell the code generation tools to generate AS3 Long, BigInteger and BigDecimal typed variables, you must enable three related options.
With the GraniteDS Eclipse builder, you will have to go to the "Options" panel and enable these three options:

With the Gas3 Ant task, you will use the following configuration:
<gas3
externalizelong="true"
externalizebiginteger="true"
externalizebigdecimal="true"
...>
...
</gas3>
Again, you may enable only one or more of these options, but you must follow the corresponding granite-config.xml configuration.
Suppose you have this kind of Java bean:
import java.math.BigDecimal; import java.math.BigInteger; public class MyBean { private BigDecimal bd; private BigInteger bi; private Long l1; private long l2; public BigDecimal getBd() { return bd; } public void setBd(BigDecimal bd) { this.bd = bd; } // other get/set... }
With all options enabled, the result of generation will be has follow:
import org.granite.math.BigDecimal;
import org.granite.math.BigInteger;
import org.granite.math.Long;
[RemoteClass(alias="path.to.MyBean")]
public class MyBean {
private var _bd:BigDecimal;
private var _bi:BigInteger;
private var _l1:Long;
private var _l2:Long;
public function get bd():BigDecimal {
return _bd;
}
public function set bd(value:BigDecimal):void {
_bd = value;
}
// other get/set...
}
With standard Gas3 configuration, the ActionScript3 type generated for each property would have been Number.
Note on Performances
ActionScript3 implementations of big numbers give reasonnable operation performances, but not as good as their Java equivalents. At this time, due to the lack of a native 64 bits type in the Flash VM, arithmetic operations of the Long, BigInteger and BigDecimal AS3 implementations rely partly on short (16 bits) native operations rather than integer 32 bits operations, in order to control overflows. This leads to overall good performances, but not as good as in Java.
