4.3. Diving into Serialization — AS3 to Java and Back

Flex talks AS3 and BlazeDS talks Java, yet they have a fluent conversation. The secret behind this smooth flow of data between the two sides is the presence of the serialization and deserialization logic elements within BlazeDS. This logic element is the one that appropriately converts data types in one language to the types in the other. To understand how this element works and how you could help it do its job well, it is worthwhile to understand how the data types on the two sides map to each other.

The simplest case of mapping arises with the simple and primitive types, for example String, Boolean, and integer. An integer in AS3 can be int or uint implying signed and unsigned integers respectively. These simple data types convert over to exact corresponding types in Java, as follows:

  • String (AS3)java.lang.String (Java)

  • Boolean (AS3)java.lang.Boolean (Java)

  • int/uint (AS3)java.lang.Integer (Java)

However, BlazeDS is smart enough to support related types as well. For example, passing in an AS3 int type to a Java method that takes java.lang.Double, java.lang.Long, primitive double, or primitive int argument will not fail, but the value will be automatically converted over to the respective data type. Similarly, an AS3 Boolean type could be forced to map to a java.lang.String type, where it would pass in "true" and "false" string values to the method.

AS3 has a Number type that holds numerical values. The numerical values can be floating point type or integral. The int and uint data types convert to a java.lang.Integer type. However, a Number defaults to a floating point type and represents a number with a decimal part. Therefore a Number maps to java.lang.Double. However, other numeric types can also receive an argument that is of a Number type. These possible numeric types in Java are:

  • java.lang.Long

  • java.lang.Float

  • java.lang.Integer

  • java.lang.Short

  • java.lang.Byte

  • java.math.BigDecimal

  • java.math.BigInteger

  • double

  • long

  • float

  • int

  • short

  • byte

On reverse flow any of the above mentioned Java numeric types, except java.lang.Integer, and int are converted to an AS3 Number. The integer types convert to an AS3 int.

AS3 Date by default maps to UTC (Universal Time) formatted java.util.Date. However an AS3 Date type passed in to a server-side method is also compatible with any of the following date and timestamp types:

  • java.util.Calendar

  • java.sql.Timestamp

  • java.sql.Time

  • java.sql.Date

Sometimes peculiar behavior can occur with numeric types when the values are null. By default, the AS3 null and undefined values pass in as null on the Java side. With AS3 Number, though, null values get converted to 0 and are passed as such. Therefore a null assignment to a Number is received as a 0-valued Java integer or double. This is not a problem at all for Java primitive types, as they take default values and cannot be set to null anyway. However, this can get tricky and troublesome when using the object types: Integer, Double, Long, and Float. In these cases, too, the value is received as a 0-valued quantity. This may not always be correct. For example, you may have a user input form in which you may ask a user to input his or her age (rounded to the closest number of years) in a form field. If the user does not enter any value into such a form field, which holds a value of type Number, then the value is actually null (or unspecified). However, a Number cannot have a null value so it converts it over to 0 and that is what the Java Integer receives at the server side. Do you see the discrepancy? Because of the error, the user who filled in the form is technically less than 6 months of age, which is not what the user said.

To handle such problems one needs to carefully choose data types and in some cases resort to extending the flex.messaging.io.BeanProxy class, which provides a means to intercept the getter and setter calls on the Java side. You could possibly have chosen an AS3 Object type for the form field in the earlier case and the exception would not have occurred. However, then the handling of regular numerical values would need more effort. So choose a data type after considering such exceptions and border cases, while understanding the possible overheads of alternatives. The extension of the BeanProxy behavior is a handy way to inject custom conversion rules. Starting with Chapter 7 (Leveraging Hibernate and JPA with Flex), you will see many examples where the BeanProxy is extended.

Although some of the border cases, such as null value handling, are challenging, many of the serialization and deserialization rules you have seen so far are straightforward. With AS3 array types, though, the conversion rules get complex.

The most sophisticated and complicated conversion rules exist for array types. AS3 arrays can either have numerical indices only or can have string values for indices as well. When indices contain only numerical types, the arrays are called strict arrays. When indices include string values, the arrays are of associative array type. Associative array types map to a java.util.Map type. Strict array indices can be continuous (starting from 0) or noncontinuous. If the indices are continuous and starting from 0 then such strict arrays are dense. Dense arrays map to a java.util.List data type. If the indices are noncontinuous (that is, there are holes or gaps between the elements), then such strict arrays are sparse. Sparse arrays map to a java.util.Map type. If they are mapped to a java.util.List type, as the dense arrays are, you may see a whole lot of null values in the list that correspond to the gaps. You don't want to waste space and computing resources, so the choice of a Map is prudent.

To reinforce what you have learned about arrays and their conversion rules so far, let's illustrate with a few simple examples. A strict and dense array in AS3 is:

var anArray:Array = new Array();
anArray[0] = "Jack";
anArray[1] = "Jill";
anArray[2] = "Hansel";
anArray[3] = "Gretel";

This array (anArray) when converted to Java would be by default of a java.util.List type. Alternatively, you could have an associative array for the same data set, defined as follows:

var anotherArray = new Array();
anotherArray["boy1"] = "Jack";
anotherArray["girl1"] = "Jill";
anotherArray[3] = "Hansel";
anotherArray[4] = "Gretel";

This associative array translates to a java.util.Map type. The indices become the keys, and the array items become the value. In some cases, a strict array also translates to a java.util.Map type. This happens when the strict array is sparse and has many gaps between its indices. You know that a sparse array translated to a java.util.List type could lead to storage of a lot of null values. A sparse array is:

var aSparseArray = new Array();
aSparseArray[1] = "Jack";
aSparseArray[2] = "Jill";
aSparseArray[34] = "Batman";
aSparseArray[35] = "Robin";

So far, only the default conversions for AS3 arrays have been elucidated. What if the method at the Java end takes in arguments of java.util.Collection type? Such a method could receive a dense AS3 Array. Depending on the interface type of the argument the following conversions are possible:

  • List—ArrayList

  • SortedSet—TreeSet

  • Set—HashSet

  • Collection—ArrayList

If the incoming array is a sparse array, then the Java method will still receive a java.util.Map type. So, it's pertinent that you closely verify the array type upfront and define your collection classes on either side of the wire. At times, one side of the puzzle may be given. In such cases, you need to reconfirm that the data structure across the wire is compatible with it.

On its way up from the server to a client a java.util.Collection type translates to an mx.collections.ArrayCollection type unless the channel is explicitly configured to convert such a collection to an AS3 Array type. BlazeDS allows specific property setting on channels for AMF serialization that support legacy, especially Flex 1.5.

While these built-in and standard types are critical for serialization, custom types or typed objects are usually the units that are passed back and forth. Typed objects, of course, have fields that can be of a custom type, a built-in type, or a standard type. Think of a "person" type with these fields: name, ID, address, and phone number. The name can be a string, the ID and the phone number can be numerical, and the address could be a custom type. An address custom type could have fields like street, city, state, and zip code, which could be string, string, string, and number respectively. Such a typed object could be represented as a Java bean type with a set of getter and setter pairs for each attribute. In addition, for BlazeDS to instantiate it on demand it needs to have a no arguments constructor. On the AS3 end such a class could again have a structure that resembles the Java bean structure of attributes with a getter and setter pair for each. The Flex framework includes a metadata type called RemoteClass that can be used to annotate AS3 classes and specify their server-side counterparts. Java server-side classes are mapped by specifying their fully qualified class name within the [RemoteClass(alias=" ")] metadata tag. The serializer and deserializer convert between AS3- and Java-typed objects using the value provided in this metadata element.

BlazeDS serializes all the bean properties and public fields of POJOs across the wire. No constants, transient properties, static properties, read-only properties, or private properties are serialized. The bean properties are introspected using the java.beans.Introspector class, which returns the property descriptors via the BeanInfo object types. A BeanInfo type specifies the methods, properties, and events of a Java bean. In addition to the bean properties that have a getter and setter pair, a POJO could contain public fields. The public fields are extracted using reflection.

On the Flex application side, the serialization and extraction is done by the Flash player. AS3 object properties, other than those that are transient, are extracted and passed across the wire.

BlazeDS translates between Java and AS3 using rules, some of which were specified and illustrated in this section. Sometimes, though, you may desire to provide custom rules for serialization.

Custom serialization is supported with the help of the flash.utils.IExternalizable at the Flash client side and java.io.Externalizable at the Java server side. On both sides the externalizable interface has readExternal and writeExternal methods for custom serialization.

On the Flash client side, two I/O interfaces define the input and output streams for reading and writing binary data. The interface for data input is IDataInput, and its counterpart for writing is IDataOutput. The IDataInput interface defines read methods for both primitive and object data types. The primitive read methods rely on built-in standard deserialization and the read object methods could utilize custom rules for deserialization. IDataOutput provides for analogous methods for writing. So, you could write primitive types and objects.

An example of custom serialization that involves IDataInput and IDataOutput within the readExternal and writeExternal methods could be like so:

public function readExternal(input:IDataInput):void {
        floatProperty1 = input.readFloat();
        object1 = input.readObject();
    }

    public function writeExternal(output:IDataOutput):void {
        output.writeFloat(floatProperty1);
        output.writeObject(object1);
    }

On the Java server side, two I/O interfaces, ObjectInput and ObjectOutput, can be used to read and write object streams. These interfaces serve the same function that IDataInput and IDataOutput serve and work with the readExternal and writeExternal methods on the Java side.

Figure 4-4 depicts custom serialization between a Flex application and a Java object on the server.

Figure 4.4. Figure 4-4

By now, you are exposed to the depths of the BlazeDS remoting service. It may be a good time to see a complete example to understand how the different pieces fit into a whole.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.47.218