2010年4月20日火曜日

作業メモ:FlexのRemotingでActionScriptからjavaに型をマッピングする方法

今回は、Flex の Remoting で ActionScript から java に型をマッピングする方法について、実際に動作を確認しながら考えてみます。

基本情報

基本的な情報は以下に書かれています。

以下、各型についてマッピングの実験をしてみます。


ActonScript to Java : Boolean, String of "true" or "false" to java.lang.Boolean

Java side test code.
public boolean asToJavaBooleanTest(boolean asBooleanTrue, boolean asBooleanFalse, boolean stringTrue, boolean stringFalse) {
    return 
        (asBooleanTrue  == true ) && 
        (asBooleanFalse == false) &&
        (stringTrue     == true ) &&
        (stringFalse    == false);
}

Flex side test code.
public static function asToJavaBooleanTest():void {
    remoteObjectWrapper.invoke(true, false, "true", "false");
}


ActonScript to Java : flash.utils.ByteArray to byte []

Java side test code.
public boolean asToJavaByteArrayTest(byte[] bytes) {
    return 
        (bytes[0] == 0 ) && 
        (bytes[1] == 1 ) && 
        (bytes[2] == 2 );
}

Flex side test code.
public static function asToJavaByteArrayTest():void {
    var byteArray:ByteArray = new ByteArray();
    byteArray.writeByte(0);
    byteArray.writeByte(1);
    byteArray.writeByte(2);
    remoteObjectWrapper.invoke(byteArray);
}


ActonScript to Java : Date to java.util.Date

Java side test code.
public boolean asToJavaDateTest(Date date) {
    return date.getTime() == 1271699264375L;
}

Flex side test code.
public static function asToJavaDateTest():void {
    var date:Date = new Date();
    date.time = 1271699264375;
    remoteObjectWrapper.invoke(date);
}


ActonScript to Java : int/uint to java.lang.Integer

Java side test code.
public boolean asToJavaIntTest(int intValue, int uintValue1, int uintValue2) {
    return
        (intValue   == -1        ) &&
        (uintValue1 == 2147483647) && // rounded from 2147483648
        (uintValue2 == 2147483647);   // rounded from 2147483649
}

Flex side test code.
public static function asToJavaIntTest():void {
    var intValue:int = -1;
    // java: Integer.MAX_VALUE = 2147483647.
    var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!
    var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!
    remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);
}

このテストの結果から、以下のことが分かります。
  • ActionScript 側 の uint は Integer.MAX_VALUE = 2147483647 よりも大きい値を扱うことができる。
  • Java 側は、Integer.MAX_VALUE より大きい値が渡されると Integer.MAX_VALUE に丸めてしまう。
  • このことから、Java との連携が決まっている場合、uint は使わないほうが無難のようです。


ActonScript to Java : Number to java.lang.Double

Java side test code.
public boolean asToJavaNumberTest(double numberValue) {
    return
        (numberValue == -1.5);
}

Flex side test code.
public static function asToJavaNumberTest():void {
    remoteObjectWrapper.invoke(new Number(-1.5));
}


ActonScript to Java : String to java.lang.String

Java side test code.
public boolean asToJavaStringTest(String stringValue1, String stringValue2, String stringValue3) {
    return
        (stringValue1.equals("")) &&
        (stringValue2.equals("foo")) &&
        (stringValue3 == null); 
}

Flex side test code.
public static function asToJavaStringTest():void {
    var stringValue1:String = "";
    var stringValue2:String = "foo";
    var undefinedValue:String;   // Note: undefined is converted to null.
    var nullValue:String = null; // Note: null is converted to null.
    remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);
}

ActionScript の undefined と null は、Java の null に変換されるようです。


ActonScript to Java : Object (generic) to java.util.Map

Java side test code.
public boolean asToJavaGenericObjectTest(Map<String,Object> nullValue, Map<String,Object> simpleObject, Map<String,Object> hasNullProperty, Map<String,Object> hasStringProperty, Map<String,Object> hasDateProperty, Map<String,Object> hasNestedProperty) {
    return
        (nullValue == null) &&
        (simpleObject != null) &&
        (hasNullProperty.get("property") == null) &&
        (hasStringProperty.get("property").equals("foo")) &&
        (Date.class.isInstance(hasDateProperty.get("property"))) &&
        (Date.class.isInstance(Map.class.cast(hasNestedProperty.get("property")).get("nestedProperty")));
}

Flex side test code.
public static function asToJavaGenericObjectTest():void {
    // null
    var nullValue:Object = null;
    
    // simple object
    var simpleObject:Object = new Object();
    
    // has null property
    var hasNullProperty:Object = new Object();
    hasNullProperty.property = null;
    
    // has String object
    var hasStringProperty:Object = new Object();
    hasStringProperty.property = "foo"
        
    // has Data object
    var hasDateProperty:Object = new Object();
    hasDateProperty.property = new Date();
    
    // has nested property
    var hasNestedProperty:Object = new Object();
    hasNestedProperty.property = new Object();
    hasNestedProperty.property.nestedProperty = new Date();
    
    remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);
}
ネストされても、特に問題なく動作するようです。


ActonScript to Java : typed Object to typed Object

private コンストラクタのみのJavaクラスを対象にしてみたところ、以下のように怒られてしまいました。
Unable to create a new instance of type 'experiment.SimpleObject'. 
Types must have a public, no arguments constructor.

ObjectFanatics 的方針としては、public のデフォルトコンストラクタの強制など容認できるはずもありません。
ということで、ソースにパッチを当てて対応しました。

引数無しの private コンストラクタが必要になってしまうのと、そのために final の変数の利用がほぼ絶望的になるという点がかなり厳しいのですが、とりあえずは妥協することにしましょう。将来的には、引数のある private コンストラクタに対応しようと思います。(TODO: 引数なしのプライベートコンストラクタを new してから値を格納する方法ではなく、private コンストラクタの引数にシリアライズされたオブジェクトを復元していく方法を実装する。)


お次は、java 側で private field に値を入れることを期待していたのですが、以下のように怒られてしまいました。
Cannot create class of type 'experiment.WithPrivateFileds'
ObjectFanatics 的方針としては、private field が使えない制約など容認できるはずもありません。

ちょっと調べてみると、こんな issue がありました。
BLZ-427 - Add configuration option for BeanProxy#includeReadOnly property.これか!?
とおもいきや、これは Java から ActionScript 側への変換に関してだけみたいですね。
しかし、BeanProxyのフィールドに対する判断基準になる設定なので、必要です。

ということで、services-config.xml ファイルのチャネル定義に serialization の設定として以下のように include-read-only オプションを追加します。
<channels>
  <channel-definition id="amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint" />
    <properties>
      <serialization>
        <include-read-only>true</include-read-only>
      </serialization>
    </properties>
  </channel-definition>
</channels>


また、ActionScript 側から渡された値を Java 側の private フィールドに格納する処理も必要です。

ということで、ソースにパッチを当てて対応しました。

Java side test code.
public boolean asToJavaTypedObjectTest(SimpleObject nullValue, SimpleObject simpleObject, SimpleObjectWithPrivateConstructor simpleObjectWithPrivateConstructor, SimpleObjectWithProperties simpleObjectWithProperties, NestableObject nestableObject, WithPrivateFiled withPrivateFiled) {
    return
        (nullValue                               == null) &&
        (simpleObject                            != null) &&
        (simpleObjectWithPrivateConstructor      != null) &&
        (simpleObjectWithProperties.intValue     == 10 ) &&
        (simpleObjectWithProperties.stringValue.equals("foo")) &&
        (simpleObjectWithProperties.simpleObject != null) &&
        (nestableObject.nestableObject.nestableObject.nestableObject == null) &&
        (withPrivateFiled.getStringValue().equals("foo"));
}

Flex side test code.
public static function asToJavaTypedObjectTest():void {
    // null
    var nullValue:Object = null;
    
    // simple object
    var simpleObject:Object = new SimpleObject();
    
    // simple object with private constructor
    var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();
    
    // simple object with properties
    var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());
    
    // nested properties
    var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));
    
    // java object has private fields
    var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");
    
    // enum
    var enumObject:EnumObject = EnumObject.KUMA_SAN;

    remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);
}


ActonScript to Java : Object to enum

基本方針は、Enums in Java to Enum Like Objects in ActionScriptと同じです。

ActionScript側ではpublicなプロパティを1つだけ持ったオブジェクトをEnumとして扱い、明示的に java 側のEnumにマッピングしないようにします。プロパティの値は java 側の Enum の name と同じにしておきます。

Java side test code.
public boolean asToJavaEnumTest(EnumObject enumValue) {
    return
        (enumValue.equals(EnumObject.KUMA_SAN));
}

Flex side test code.
public static function asToJavaEnumTest():void {
    var enumValue:EnumObject = EnumObject.KUMA_SAN;
    remoteObjectWrapper.invoke(enumValue);
}


以下、未検証
  • Array (dense) to java.util.List
  • Array (sparse) to java.util.Map
  • XML to org.w3c.dom.Document
  • XMLDocument(legacy XML type)  to org.w3c.dom.Document


Patch for Private Constructor

変更前
110: Object instance = cls.newInstance();

変更後
try {
    instance = cls.newInstance();
} catch (IllegalAccessException e){
    for (Constructor<? extends Object> constructor : cls.getDeclaredConstructors()) {
        if (constructor.getParameterTypes().length != 0) continue;
        constructor.setAccessible(true);
        instance = constructor.newInstance();
        break;
    }
    if (instance == null) throw e;
}



Patch for Private Field Serialization

flex.messaging.io.BeanProxy#setValue(Object instance, String propertyName, Object value)
public void setValue(Object instance, String propertyName, Object value)
    {
        BeanProperty bp = getBeanProperty(instance, propertyName);

        if (bp != null)
        {
// patch for private field.
//            if (bp.isWrite())
//            {
                try
                {
                    Class desiredPropClass = bp.getType();
                    TypeMarshaller marshaller = TypeMarshallingContext.getTypeMarshaller();
                    value = marshaller.convert(value, desiredPropClass);
                    ClassUtil.validateAssignment(instance, propertyName, value);
                    bp.set(instance, value);
                }
                catch (Exception e)
                {
                    SerializationContext context = getSerializationContext();

                    // Log ignore failed property set errors
                    if (Log.isWarn() && logPropertyErrors(context))
                    {
                        Logger log = Log.getLogger(LOG_CATEGORY);
                        log.warn("Failed to set property {0} on type {1}.",
                                new Object[] {propertyName, getAlias(instance)}, e);
                    }

                    if (!ignorePropertyErrors(context))
                    {
                        // Failed to get property '{propertyName}' on type '{className}'.
                        MessageException ex = new MessageException();
                        ex.setMessage(FAILED_PROPERTY_WRITE_ERROR, new Object[] {propertyName, getAlias(instance)});
                        ex.setRootCause(e);
                        throw ex;
                    }
                }
// patch for private field.
//            }
//            else
//            {
//                SerializationContext context = getSerializationContext();
//
//                if (Log.isWarn() && logPropertyErrors(context))
//                {
//                    Logger log = Log.getLogger(LOG_CATEGORY);
//                    log.warn("Property {0} not writable on class {1}",
//                            new Object[] {propertyName, getAlias(instance)});
//                }
//
//                if (!ignorePropertyErrors(context))
//                {
//                    //Property '{propertyName}' not writable on class '{alias}'.
//                    MessageException ex = new MessageException();
//                    ex.setMessage(NON_WRITABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});
//                    throw ex;
//                }
//            }
        }
        else
        {
            SerializationContext context = getSerializationContext();

            if (Log.isWarn() && logPropertyErrors(context))
            {
                Logger log = Log.getLogger(LOG_CATEGORY);
                log.warn("Ignoring set property {0} for type {1} as a setter could not be found.",
                            new Object[] {propertyName, getAlias(instance)});
            }

            if (!ignorePropertyErrors(context))
            {
                // Property '{propertyName}' not found on class '{alias}'.
                MessageException ex = new MessageException();
                ex.setMessage(UNKNOWN_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});
                throw ex;
            }
        }
    }


Test source code(Java)

experiment/EnumObject.java
package experiment;

public enum EnumObject {
    KUMA_SAN("くまさん"),
    TANUKI_SAN("たぬきさん");
    private final String string;
    private EnumObject(String string) {
        this.string = string;
    }
}

experiment/NestableObject.java
package experiment;

public class NestableObject {
    public NestableObject nestableObject;
    private NestableObject(){}
    public NestableObject(NestableObject nestableObject) {
        this.nestableObject = nestableObject;
    }
}

experiment/SerializationTestService.java
package test {    
    import flash.utils.ByteArray;
    
    import mx.controls.Alert;

    public final class SerializationTestService {
        private static var remoteObjectWrapper:RemoteObjectWrapper = new RemoteObjectWrapper("SerializationTestService");
        
        public static function asToJavaBooleanTest():void {
            remoteObjectWrapper.invoke(true, false, "true", "false");
        }
        
        public static function asToJavaByteArrayTest():void {
            var byteArray:ByteArray = new ByteArray();
            byteArray.writeByte(0);
            byteArray.writeByte(1);
            byteArray.writeByte(2);
            remoteObjectWrapper.invoke(byteArray);
        }
        
        public static function asToJavaDateTest():void {
            var date:Date = new Date();
            date.time = 1271699264375;
            remoteObjectWrapper.invoke(date);
        }
        
        public static function asToJavaIntTest():void {
            var intValue:int = -1;
            // java: Integer.MAX_VALUE = 2147483647.
            var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!
            var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!
            remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);
        }
        
        public static function asToJavaNumberTest():void {
            remoteObjectWrapper.invoke(new Number(-1.5));
        }
        
        public static function asToJavaStringTest():void {
            var stringValue1:String = "";
            var stringValue2:String = "foo";
            var undefinedValue:String;   // Note: undefined is converted to null.
            var nullValue:String = null; // Note: null is converted to null.
            remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);
        }
        
        public static function asToJavaGenericObjectTest():void {
            // null
            var nullValue:Object = null;
            
            // simple object
            var simpleObject:Object = new Object();
            
            // has null property
            var hasNullProperty:Object = new Object();
            hasNullProperty.property = null;
            
            // has String object
            var hasStringProperty:Object = new Object();
            hasStringProperty.property = "foo"
                
            // has Data object
            var hasDateProperty:Object = new Object();
            hasDateProperty.property = new Date();
            
            // has nested property
            var hasNestedProperty:Object = new Object();
            hasNestedProperty.property = new Object();
            hasNestedProperty.property.nestedProperty = new Date();
            
            remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);
        }
        
        public static function asToJavaTypedObjectTest():void {
            // null
            var nullValue:Object = null;
            
            // simple object
            var simpleObject:Object = new SimpleObject();
            
            // simple object with private constructor
            var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();
            
            // simple object with properties
            var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());
            
            // nested properties
            var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));
            
            // java object has private fields
            var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");
            
            // enum
            var enumObject:EnumObject = EnumObject.KUMA_SAN;

            remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);
        }
        
        public static function asToJavaEnumTest():void {
            var enumValue:EnumObject = EnumObject.KUMA_SAN;
            remoteObjectWrapper.invoke(enumValue);
        }
        
        private static function createResultHandler(methodName:String):Function {
            return function(result:Boolean):void{Alert.show("methodName : " + (result ? "passed" : "failed"))}
        }
    }
}

experiment/SimpleObject.java
package experiment;

public class SimpleObject {
}

experiment/SimpleObjectWithPrivateConstructor.java
package experiment;

public class SimpleObjectWithPrivateConstructor {
    private SimpleObjectWithPrivateConstructor(){};
}

experiment/SimpleObjectWithProperties.java
package experiment;

public class SimpleObjectWithProperties {
    public int intValue;
    public String stringValue;
    public SimpleObject simpleObject;
    private SimpleObjectWithProperties(){}
    public SimpleObjectWithProperties(int intValue, String stringValue, SimpleObject simpleObject) {
        this.intValue = intValue;
        this.stringValue = stringValue;
        this.simpleObject = simpleObject;
    }    
}

experiment/WithPrivateFiled.java
package experiment;

public class WithPrivateFiled {
    private String stringValue;
    private WithPrivateFiled(){}
    public WithPrivateFiled(String stringValue) { this.stringValue = stringValue; }
    public String getStringValue() { return stringValue; }
}


Test source code(Flex)

test/EnumObject.as
package test {
    
    [RemoteClass(alias="experiment.EnumObject")]
    public class EnumObject {
        
        // Enum constants
        public static const KUMA_SAN:EnumObject = new EnumObject("KUMA_SAN", "くまさん");
        public static const TANUKI_SAN:EnumObject = new EnumObject("TANUKI_SAN", "たぬきさん");
        
        // Enum name. This must be public and not static valiable.
        public var val:String;
        
        [Transient]
        public var string:String;
        
        // Constructor
        public function EnumObject(name:String, string:String) {
            this.val = name;
            this.string = string;
        }
        
        // for displaying.
        public function toString():String {
            return string;
        }
        
        // use equality instead of identity because of the limitation of ActionScript.
        public function equals(object:Object):Boolean {
            return this.toString() == object.toString();
        }
    }
}

test/NestableObject.as
package test {
    
    [RemoteClass(alias="experiment.NestableObject")]
    public class NestableObject {
        
        // nested value
        public var nestableObject:NestableObject;
        
        // constructor
        public function NestableObject(nestableObject:NestableObject) {
            this.nestableObject = nestableObject;
        }
    }
}

test/RemoteObjectWrapper.as
package test {
    import mx.controls.Alert;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.remoting.Operation;
    import mx.rpc.remoting.RemoteObject;

    public class RemoteObjectWrapper {
        private var remoteObject:RemoteObject;
        public function RemoteObjectWrapper(destination:String):void {
            this.remoteObject = new RemoteObject(destination);
        }
        public function invoke(...args):void {
            var mathodName:String = getCallerSimpleName();
            remoteObject[mathodName].addEventListener("result", function (event:ResultEvent):void{Alert.show(mathodName + " : " + (event.result ? "passed" : "failed"))});
            remoteObject.addEventListener(FaultEvent.FAULT, function(faultEvent:FaultEvent):void{Alert.show("Fault : " + faultEvent)});
            var operation:Operation = remoteObject[mathodName];
            operation.arguments = args;
            operation.send();
        }
        private function getCallerSimpleName():String {
            var block:String = new Error().getStackTrace().split("at ")[3];
            var startIndex:int = block.indexOf("at ");// start of first line
            var endIndex:int = block.indexOf("()");   // end of function name
            var fullName:String = block.substring(startIndex + 3, endIndex);
            var callerSimpleName:String = fullName.substring(fullName.indexOf("/") + 1, endIndex);
            return callerSimpleName; // this is caller's caller.
        }
    }
}

test/SerializationTestService.as
package test {    
    import flash.utils.ByteArray;
    
    import mx.controls.Alert;

    public final class SerializationTestService {
        private static var remoteObjectWrapper:RemoteObjectWrapper = new RemoteObjectWrapper("SerializationTestService");
        
        public static function asToJavaBooleanTest():void {
            remoteObjectWrapper.invoke(true, false, "true", "false");
        }
        
        public static function asToJavaByteArrayTest():void {
            var byteArray:ByteArray = new ByteArray();
            byteArray.writeByte(0);
            byteArray.writeByte(1);
            byteArray.writeByte(2);
            remoteObjectWrapper.invoke(byteArray);
        }
        
        public static function asToJavaDateTest():void {
            var date:Date = new Date();
            date.time = 1271699264375;
            remoteObjectWrapper.invoke(date);
        }
        
        public static function asToJavaIntTest():void {
            var intValue:int = -1;
            // java: Integer.MAX_VALUE = 2147483647.
            var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!
            var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!
            remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);
        }
        
        public static function asToJavaNumberTest():void {
            remoteObjectWrapper.invoke(new Number(-1.5));
        }
        
        public static function asToJavaStringTest():void {
            var stringValue1:String = "";
            var stringValue2:String = "foo";
            var undefinedValue:String;   // Note: undefined is converted to null.
            var nullValue:String = null; // Note: null is converted to null.
            remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);
        }
        
        public static function asToJavaGenericObjectTest():void {
            // null
            var nullValue:Object = null;
            
            // simple object
            var simpleObject:Object = new Object();
            
            // has null property
            var hasNullProperty:Object = new Object();
            hasNullProperty.property = null;
            
            // has String object
            var hasStringProperty:Object = new Object();
            hasStringProperty.property = "foo"
                
            // has Data object
            var hasDateProperty:Object = new Object();
            hasDateProperty.property = new Date();
            
            // has nested property
            var hasNestedProperty:Object = new Object();
            hasNestedProperty.property = new Object();
            hasNestedProperty.property.nestedProperty = new Date();
            
            remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);
        }
        
        public static function asToJavaTypedObjectTest():void {
            // null
            var nullValue:Object = null;
            
            // simple object
            var simpleObject:Object = new SimpleObject();
            
            // simple object with private constructor
            var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();
            
            // simple object with properties
            var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());
            
            // nested properties
            var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));
            
            // java object has private fields
            var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");
            
            // enum
            var enumObject:EnumObject = new EnumObject("");

            remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);
        }
        
        public static function asToJavaEnumTest():void {
            var enumValue:EnumObject = EnumObject.KUMA_SAN;
            remoteObjectWrapper.invoke(enumValue);
        }
        
        private static function createResultHandler(methodName:String):Function {
            return function(result:Boolean):void{Alert.show("methodName : " + (result ? "passed" : "failed"))}
        }
    }
}

test/SerializationTestServiceApp.mxml
<?xml version="1.0" encoding="utf-8"?>
<!-- Application to invoke serialization tests. -->

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%">
    <s:layout>
        <s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/>
    </s:layout>
    <fx:Script>
        <![CDATA[
            import test.SerializationTestService;
            protected function test():void {
                SerializationTestService.asToJavaBooleanTest();
                SerializationTestService.asToJavaByteArrayTest();
                SerializationTestService.asToJavaDateTest();
                SerializationTestService.asToJavaIntTest();
                SerializationTestService.asToJavaNumberTest();
                SerializationTestService.asToJavaStringTest();
                SerializationTestService.asToJavaGenericObjectTest();
                SerializationTestService.asToJavaTypedObjectTest();
                SerializationTestService.asToJavaEnumTest();
            }
        ]]>
    </fx:Script>
    <s:Button id="testButton" label="Test" click="test()"/>
</s:Application>

test/SimpleObject.as
package test {
    [RemoteClass(alias="experiment.SimpleObject")]
    public class SimpleObject {
        public function SimpleObject() {}
    }
}

test/SimpleObjectWithPrivateConstructor.as
package test {
    [RemoteClass(alias="experiment.SimpleObjectWithPrivateConstructor")]
    public class SimpleObjectWithPrivateConstructor {
        public function SimpleObjectWithPrivateConstructor() {
        }
    }
}

test/SimpleObjectWithProperties.as
package test {
 [RemoteClass(alias="experiment.SimpleObjectWithProperties")]
 public class SimpleObjectWithProperties {
  
  // properties
  public var intValue:int;
  public var stringValue:String;
  public var simpleObject:SimpleObject;
  
  // constructor
  public function SimpleObjectWithProperties(intValue:int, stringValue:String, simpleObject:SimpleObject):void {
   this.intValue = intValue;
   this.stringValue = stringValue;
   this.simpleObject = simpleObject;
  }
 }
}

test/WithPrivateFiled.as
package test {
    [RemoteClass(alias="experiment.WithPrivateFiled")]
    public class WithPrivateFiled {
        
        // The field of ActionSide is public. Java side of that is private.
        public var stringValue:String;
        
        // constructor
        public function WithPrivateFiled(stringValue:String) {
            this.stringValue = stringValue;
        }
    }
}

0 件のコメント:

コメントを投稿