基本事項
基本的な設定やその他基本事項については、以下に準じます。
- 作業ログ: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 件のコメント:
コメントを投稿