続 JavaFX のリフレクション

今回もリフレクションの勉強です。
次のプログラムはオブジェクトのメンバー(フィールド、メソッド)に対する基本的なアクセスを行います。

プログラム例その3

package fooami;

import javafx.reflect.*;

/**
 * リフレクションによるオブジェクトのメンバーアクセス。
 * @author hide1080
 */

function run(args: String[]) {
    // Foo オブジェクトを生成
    var who = Foo {};
    println(who);

    // カレントVM の FXContext (実装クラスは FXLocal.Context) の
    // シングルトンインスタンスを取得
    var context = FXLocal.getContext();

    // Foo に対する FXClassType と FXObjectValue を取得
    var clazz = context.findClass("fooami.MemberReflection$Foo");
    var objValue =  context.mirrorOf(who);

    // FXVarMember を介して Foo オブジェクトの name フィールドを変更
    var varMember = clazz.getVariable("name");
    varMember.setValue(objValue, context.mirrorOf("Gonbe"));
    println(who);

    // FXFunctionMember を介して Foo オブジェクトの setName() メソッドを実行
    var fncMember = clazz.getFunction("setName", context.getStringType());
    fncMember.invoke(objValue, context.mirrorOf("Foo am I?"));
    println(who);

    // FXObjectValue の invoke() メソッドでも実行できる
    objValue.invoke(fncMember, context.mirrorOf("hide1080"));
    println(who);
}

class Foo {
    var name = "Nanasi";
    function setName(nm: String): Void {
        name = nm;
    }
    public override function toString(): String {
        return "Foo: {name}";
    }
}
プログラム例その3の結果
c:\WORK\fx>javafxc fooami\MemberReflection.fx

c:\WORK\fx>javafx fooami.MemberReflection
Foo: Nanasi
Foo: Gonbe
Foo: Foo am I?
Foo: hide1080


次は Jim おじさんのエントリをヒントに書いたプログラムです。

プログラム例その4

package fooami;

import javafx.reflect.*;

/**
 * リフレクションによる Stage, Scene, Text の作成。
 * @author hide1080
 */

function run(args: String[]) {
    // カレントVM の FXContext (実装クラスは FXLocal.Context) の
    // シングルトンインスタンスを取得
    var context = FXLocal.getContext();

    // リフレクションで javafx.scene.text.Text を作成
    var clazz = context.findClass("javafx.scene.text.Text");
    var objValue =  clazz.allocate();
    objValue.initVar("x", context.mirrorOf(30.0));
    objValue.initVar("y", context.mirrorOf(30.0));
    objValue.initVar("content", context.mirrorOf("Hello, Reflection's World!"));
    objValue = objValue.initialize();
    var objValueText = objValue;

    // リフレクションで javafx.scene.Scene を作成
    clazz = context.findClass("javafx.scene.Scene");
    objValue =  clazz.allocate();
    objValue.initVar("width", context.mirrorOf(200.0));
    objValue.initVar("height", context.mirrorOf(100.0));
    objValue = objValue.initialize();
    // initVar でシーケンスタイプのフィールドを初期化しようとすると
    // 内部で FXLocal.SequenceValue から FXLocal.ObjectValue への ClassCastException
    // となってしまうので FXVarMember を介してシーケンスを設定するようにした
    var seqValue = context.makeSequence(objValueText.getType(), objValueText);
    var varMember = clazz.getVariable("content");
    varMember.setValue(objValue, seqValue);
    var objValueScene = objValue;

    // リフレクションで javafx.stage.Stage を作成
    clazz = context.findClass("javafx.stage.Stage");
    objValue =  clazz.allocate();
    objValue.initVar("title", context.mirrorOf("Reflection Example"));
    objValue.initVar("scene", objValueScene);
    objValue = objValue.initialize();
    var stage = (objValue as FXLocal.Value).asObject();

    return stage;
}
プログラム例その4の結果


見ての通りですがやっぱりリフレクションを使用すると冗長で複雑なプログラムになってしまいます。
一般のアプリケーションで使用することは殆ど無いでしょう。
僕もまだあまりよく見えていませんが、JavaFX において、用途としてはツールや特殊なライブラリ、実行時の状態の監視などとなるでしょうか。