基本事項
基本的な設定やその他基本事項については、以下に準じます。
- 作業ログ:GAE/J + BlazeDS 4 環境について考えてみた。
- 作業ログ:login機能使用時の SessionDuplicate 問題
- 作業メモ:FlexのRemotingでActionScriptからjavaに型をマッピングする方法
- 作業メモ:FlexのRemotingでjavaからにActionScript型をマッピングする方法
ActionScript 側の enum 名格納変数について
ActionScript 側の enum 名格納変数を name とします。AMFで通信される情報も java の Enum#name() に準じたものにします。そのため、以下のような独自のEnumProxyを定義します。
package com.objectfanatics.flex.messaging.io; import java.util.Collections; import java.util.List; import flex.messaging.io.AbstractProxy; import flex.messaging.io.BeanProxy; public class EnumProxy extends BeanProxy { private static final String ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME = "name"; private static final List<String> propertyNames = Collections.singletonList(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME); @SuppressWarnings("unchecked") public Object createInstance(String className) { return new EnumStub((Class<Enum>) AbstractProxy.getClassFromClassName(className)); } public Object getValue(Object instance, String propertyName) { if (propertyName.equals(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME)) { return Enum.class.cast(instance).name(); } else { throw new IllegalArgumentException("No property named: " + propertyName + " on enum type"); } } public void setValue(Object instance, String propertyName, Object value) { if (propertyName.equals(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME)) { EnumStub.class.cast(instance).value = String.class.cast(value); } else { throw new IllegalArgumentException("no EnumStub property: " + propertyName); } } @SuppressWarnings("unchecked") public Object instanceComplete(Object instance) { EnumStub es = EnumStub.class.cast(instance); return Enum.valueOf((Class) es.cl, es.value); } @SuppressWarnings("unchecked") public List getPropertyNames(Object instance) { if (!(instance instanceof Enum)) { throw new IllegalArgumentException("getPropertyNames called with non Enum object"); } else { return propertyNames; } } private class EnumStub { private Class<?> cl; private String value; private EnumStub(Class<?> c) { cl = c; } } }
同時に HttpFlexSession の static ブロックで以下のように定義し、あらゆる Enum 型に対して EnumProxy が適用されるようにします。
// patch for enum serialization static { PropertyProxyRegistry.getRegistry().register(Enum.class, new EnumProxy()); }
ActionScript 側の enum ルール
ActionScript 側の enum は、以下のような形式で作成します。
// Sample enum class. package com.objectfanatics.englishfanatics.dataobject { import com.objectfanatics.flex.EnumBase; // fqcn of java counterpart enum class [RemoteClass(alias="com.objectfanatics.sample.SampleEnum")] // class name should be the same as the name of the java counterpart enum class. public class SampleEnum extends EnumBase { // enums // - const name and the value of the first parameter of the constructor should be the same. public static const KUMA_SAN:SampleEnum = new SampleEnum("KUMA_SAN", "くまさん"); public static const TANUKI_SAN:SampleEnum = new SampleEnum("TANUKI_SAN", "たぬきさん"); // constructor // - default parameter values are required for deserialized enums. // - this must be invoked only for enum constant creation in this class and deserialized enum creation. public function SampleEnum(name:String = null, string:String = null) { super(name, string); } // returns all enum constants in this class. // - this method is workaround for ActionScript3.0's limitation. // static methods are not inherited and cannot be overridden in ActionScript 3.0. public static function values():Array { return superValues(); } } }
すべての enum は下記のベースクラスを継承します。
package com.objectfanatics.flex { import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; /** * Base class of enum object. */ public class EnumBase { // key = enum class name, value = enum array. private static const valuesMap:Object = new Object(); // enum class name private var enumClassName:String; // enum name public var name:String; // string for presentation protected var string:String; public function EnumBase(name:String = null, string:String = null) { this.name = name; this.string = string; enumClassName = getQualifiedClassName(this); if (string != null) { // for normal enum var values:Array = valuesMap[enumClassName]; if (values == null) values = new Array(); valuesMap[enumClassName] = values; values.push(this); } else { // for deserialized enum return; } } // This method name is weird because of ActionScript 3.0's limitation. // - Static methods are not inherited and cannot be overridden in ActionScript 3.0. public static function superValues():Array { // TODO: check. var blocks:Array = new Error().getStackTrace().split("at "); var block:String = blocks[2]; var startIndex:int = block.indexOf("at ");// start of first line var endIndex:int = block.indexOf("$"); // end of class name var enumClassName:String = block.substring(startIndex + 1, endIndex); return valuesMap[enumClassName]; } public function toString():String { if (string == null) { var enumClass:Class = getDefinitionByName(enumClassName) as Class; this.string = enumClass[name].string; } return string; } //use equality instead of identity. public function equals(other:EnumBase):Boolean { return this.name == other.name; } } }
java 側の enum ルール
Java 側の enum は、ActionScript 側の name プロパティと Java 側の Enum#name() の値が対応していれば、どのような形でもかまいません。
以下例。
package com.objectfanatics.sample; public enum SampleEnum { KUMA_SAN, TANUKI_SAN; }
(´・ω・`) まだまともにに使ってないから、落とし穴がいっぱいありそうな気がする今日この頃。
0 件のコメント:
コメントを投稿