Accessibility

Table of Contents

Exchanging Complex Data with Back-End Systems

Using RemoteObject

The RemoteObject service allows you to invoke methods remotely in Java objects deployed in your application server. Flex.NET, currently in beta, will allow you to remotely invoke methods in .NET objects.

When invoking methods remotely, you can pass objects back and forth (as the methods' input parameters and return value) between the client and the server.

The RemoteObject approach makes particular sense when both the front end and the back end of your application manipulate data as objects. In this case, the intermediate step of converting objects to XML may result in unnecessary overhead.

When you use RemoteObject, Flex takes care of the serialization/deserialization process. The RemoteObject uses AMF (Action Message Format) over HTTP. AMF is a binary encoding format that makes this solution faster and leaner in terms of bandwidth usage than the other solutions, especially when manipulating large data sets.

In the RemoteObject implementation of the Employee Directory application, we use a Java class named EmployeeService. The EmployeeService class is defined as follows:

package samples.data;

public class EmployeeService {

    public void addEmployee(EmployeeVO employee) {
        // Output data to console for demo purpose
        System.out.println("First Name: "+employee.getFirstName());
        System.out.println("Last Name: "+employee.getLastName());
        System.out.println("Salary: "+employee.getSalary());
        System.out.println("Start Date: "+employee.getStartDate());
        System.out.println("Phone Numbers:");
        PhoneNumberVO[] phoneNumbers=employee.getPhoneNumbers();
        PhoneNumberVO phoneNumber=null;
        for (int i=0; i<phoneNumbers.length; i++) {
            phoneNumber = phoneNumbers[i];
            System.out.println(phoneNumber.getType()+": "+phoneNumber.getNumber());
        }
        // Some business logic to process the data
    }

}

The addEmployee() method takes an EmployeeVO object as an argument. The EmployeeVO class is defined as follows:

package samples.data;

import java.util.Date;

public class EmployeeVO {

    private String firstName;
    private String lastName;
    private int salary;
    private Date startDate;

    private PhoneNumberVO[] phoneNumbers;

    // getter and setter methods not shown for brevity     

}

The PhoneNumberVO class referenced in EmployeeVO is defined as follows:

package samples.data;

public class PhoneNumberVO {

    private String type;
    private String number;

    // getter and setter methods not shown for brevity     

}

When remotely invoking the addEmployee() method in the client application, you need to make sure that the ActionScript object you pass as an argument is deserialized into an instance of the EmployeeVO class at the server side. Similarly, you need to make sure that the PhoneNumber objects you pass as part of the Employee object are deserialized into instances of the PhoneNumberVO class.

There are three basic rules to make sure an ActionScript object passed as a method parameter is deserialized into an instance of a specific Java class:

  • You need to declare the ActionScript/Java class mapping using the Object.RegisterClass() static function. For example:

    Object.registerClass("samples.data.EmployeeVO", samples.data.EmployeeVO); 

    The first argument is the fully qualified Java class name; the second argument is the ActionScript class.

  • You have to provide the ActionScript class attributes with the exact same names (and same letter case) as the Java class attributes.
  • You have to map the data types of the ActionScript class attributes to the data types of the Java class attributes. (Refer to the ActionScript/Java data type mapping table in the documentation for more details.)

In addition, even though it's not required, it's often considered a good practice to provide your ActionScript and Java classes with the same class and package names.

The same three rules also allow a Java object returned by remote method invocation to be deserialized into an object of a specific ActionScript class. (By default, an object returned from the server is deserialized into an instance of the ActionScript Object class.)

Here is the implementation of the Employee Directory using RemoteObject:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
    backgroundColor="#FFFFFF"
    initialize="initApp()">

    <mx:Script>
        import samples.data.*;

        var employee: EmployeeVO;

        function initApp() {
            employee=new EmployeeVO();
            employee.phoneNumbers=new Array();
        }

        function addEmployee() {
            employee.firstName=firstName.text;
            employee.lastName=lastName.text;
            employee.startDate=startDate.selectedDate;
            employee.salary=Number(salary.text);
            srv.addEmployee(employee);
        }

    </mx:Script>

    <mx:RemoteObject id="srv" source="samples.data.EmployeeService">
        <mx:method name="addEmployee"/>
    </mx:RemoteObject>

    <mx:Form>

        <mx:FormItem label="First Name">
            <mx:TextInput id="firstName"/>
        </mx:FormItem>
        <mx:FormItem label="Last Name">
            <mx:TextInput id="lastName"/>
        </mx:FormItem>
        <mx:FormItem label="Salary">
            <mx:TextInput id="salary"/>
        </mx:FormItem>
        <mx:FormItem label="Start Date">
            <mx:DateField id="startDate"/>
        </mx:FormItem>

        <mx:FormItem label="Phone Numbers" verticalGap="1">
            <mx:DataGrid id="dg" editable="true"
                dataProvider="{employee.phoneNumbers}" >
                <mx:columns>
                    <mx:Array>
                        <mx:DataGridColumn columnName="type" headerText="Type" 
                            cellRenderer="PhoneTypeRenderer"/>
                        <mx:DataGridColumn columnName="number" headerText="Number"/>
                    </mx:Array>
                </mx:columns>
            </mx:DataGrid>
            <mx:HBox horizontalGap="1" width="100%" horizontalAlign="right">
                <mx:Button label="+" click="dg.addItem(new PhoneNumberVO('H'))" 
                    cornerRadius="0" borderThickness="0" width="20" height="20"/>
                <mx:Button label="-" click="dg.removeItemAt(dg.selectedIndex)" 
                    cornerRadius="0" borderThickness="0" width="20" height="20"/>
            </mx:HBox>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button label="Add Employee" click="addEmployee()"/>
        </mx:FormItem>

    </mx:Form>

</mx:Application>

EmployeeVO.as is defined as follows:

class samples.data.EmployeeVO {

    public var firstName : String;
    public var lastName : String;
    public var phoneNumbers : Array;
    public var salary : Number;
    public var startDate : Date;

    static var registered=
Object.registerClass("samples.data.EmployeeVO", samples.data.EmployeeVO);

}

PhoneNumberVO.as is defined as follows:

class samples.data.PhoneNumberVO {

    public var number : String;
    public var type : String;

    static var registered=
Object.registerClass("samples.data.PhoneNumberVO", samples.data.PhoneNumberVO);

    function PhoneNumberVO(type: String) {
        this.type=type;
    }

}

Creating ActionScript classes based on existing Java classes can be a tedious and error-prone task. To facilitate my own development efforts, I created a simple utility that uses Java introspection to create automatically an ActionScript class based on a Java Value Object class. This utility, named java2as, is included in the supporting ZIP file in the Requirements section.