JavaServiceInvokerはなぜASObjectをJavaBeansにマッピングしないか

#書いてある内容が間違ってたらツッコミお願いします。

一言ですませるなら、OpenAMFは呼び出し先のメソッドの判定方法が若干甘い!!という事です。

一言で済ませた後に長々と説明しましょう。これはOpenAMFの内部の動きを知る必要があります。OpenAMFFlashから送られてきたオブジェクトをFlashから送られてくる情報を元にJavaBeansに変換しているわけではありません。Flashから送られてくる「クラス名、メソッド名、引数の数」を元に呼び出し先のクラスを走査し、呼び出し先のメソッドを捜し当てます。探し当てたメソッドの引数の型を元に、Flashから来たオブジェクトを変換しているのです。まとめると、呼び先を特定して、呼び先の情報を元に、送られてきたオブジェクトを変換しているという事です。

ではなぜASObjectをJavaBeansにマッピングできない事があるのか。そうです、必ず変換できないわけでは無いんです。私はOpenAMFの特性を利用して少しいじわるなクラスを作り、それをFlashから呼び出すようなコードを書きました。そのコードとは下記のようなクラスです。

public class InvokeTest {
  public void test(ASObject asObject) {
  }
  public void test(TestJavaBeans beans) {
  }
}

つまり引数の数が同じで、引数の型が違う、JavaBeansより前にASObjectが引数のメソッドが宣言されている。

OpenAMFはメソッドの定義順にFlashが呼び出そうとしているメソッドを評価します。先の説明の通り、クラス名、メソッド名、引数の数がマッチすれば、それは呼び出したいメソッドだと評価します。ここで肝となるのが引数の型は見ていないという事です。呼び出し先のメソッドを決定する際に、引数の型は決定していないのです。なぜならFlash側からは引数の型をサーバへ送信していないから。なので先に説明した3つの条件が一致すれば、OpenAMFはメソッドを決定してしまいます。

上記の例の場合、Flashが呼び出したいメソッドはtest(ASObject)メソッドだと決定し、引数の変換を開始します。なのでASObjectは正しくJavaBeansへ変換されません。これがオーバーライドされているいじわるなメソッドが無い場合、正しくJavaBeansへ変換されます。

OpenAMFはクライアントから送られてきたオブジェクトがASObjectだと認識した後に、getType()メソッドを呼び出し、なんらかのクラス名が設定されていれば、そのクラスへと変換を試みるのですが、AS1までは_remoteClassなんていうサーバサイドの変換先のJavaBeansを設定するような仕様はありませんでした。OpenAMFはまだ_remoteClassを参照し、JavaBeansへ変換する機能がありません。将来きっと_remoteClassを参照してJavaBeansへ変換する機能が追加されると期待していますが。

ここでAS2クラスをちゃんとJavaBeansに変換するにはOpenAMFにどういう手を加えれば良いのでしょうか?OpenAMFのDecoderをいじったり、様々な所に手を入れた結果、最も簡単であろう結論が出ました。それは、ASObjectに_remoteClassというプロパティが存在していれば、setTypeメソッドを使用して_remoteClassの内容をASObjectに設定するというものです。getTypeメソッドの動作を上記動作に作り変えてしまえば、全てが丸くおさまってしまうのですが、あくまで私が作っているのはOpenAMFのServiceInvoker。大元のコードには一切手を加えないという信念の元、外部よりsetTypeメソッドを使用して、typeの設定をする事にしました。ちなみにtypeを設定した後、OpenAMFUtilsのdecodeParameterメソッドを呼び出さなければ変換は行われません。一連の処理が終り、うまく変換できなかったASObjectを取得して、_remoteClassの内容を設定し、もういちど変換をかけて正しくJavaBeansへ変換してもらおうというのが私の書いた処理です。getTypeによってどのように動作が変わるかはOpenAMFUtilsのdecodeParameterメソッドを見てください。その中からぐーんとドリルダウンしてASTranslatorのDecoderFactoryのdecideClassToTranslateIntoメソッドで使用されています。詳しい動作については…ソースをご覧ください(うわつ、ここまで来て手抜き)

最初にAS2対応の作業を行った時は、OpenAMFからASTranslatorまで様々な所に手を入れてしまったのですが、四苦八苦しているうちに作り所が見えてきて、上記のような対応が最も簡単でOpenAMFにもASTranslatorにも影響が無いという判断ができました。こんな事を実験したり、書いたりする時間がある事をとても幸せだと感じます!