ダイナミックインポートを使うことで、”必要なときだけ”必要なパッケージをインポートすることができます。これによって、アプレット起動などのパフォーマンスを向上させることができます。
以下が例となります。
|| pはPackageクラス(ここではCOM.CURL.CDK.SQLITEパッケージをインポート) def p = {import-package {make-package-selector “COM.CURL.CDK.SQLITE”}} || SQLiteDatabaseクラスを取得 def SD = {p.lookup “SQLiteDatabase”, check-imports? = true} def the-database = {SD {url “test.db”}} || SQLiteDatabaseのインスタンス生成(コンストラクタの呼出) {the-database.execute |” CREATE TABLE IF NOT EXISTS orb_simple_cache ( name VARCHAR, key VARCHAR, value BLOB, PRIMARY KEY (name, key)) “| } || SQLiteDatabase.executeメソッドの呼出 |
ダイナミックインポートを利用するには、import-packageを利用して、Packageクラスのオブジェクトを取得します。(ちなみにその引数で対象のパッケージを選択するために、make-package-selectorを使うことができます。)
注意) このとき、上記の方法の場合、マニフェストにパッケージを指定する必要があります。マニフェストにパッケージを記述したくない場合は、import-packageのキーワード引数のmanifestにパッケージファイルのurl(パス)を指定します。
対象のPackageオブジェクトから、そのプロシージャやクラスを取得するには、Package.lookupを利用します。(もしパッケージに新しいプロシージャやクラスなどを追加したい場合は、Package.addを使うことで動的に追加できます。)
また以下の例のようにevaluateプロシージャ内でもダイナミックインポートしたパッケージをPackageオブジェクト(正確にはOpenPackage)を利用できます。(evaluateのpackageキーワード引数)
|| pはPackageクラス(ここではCOM.CURL.CDK.SQLITEパッケージをインポート) def p = {import-package {make-package-selector “COM.CURL.CDK.SQLITE”}} || evaluateでも利用できます。 {evaluate || ここにコード , package = p asa OpenPackage }
|
その他関連APIとして、dynamic-lookupなどを参照ください。
Curlでのリフレクションの使用方法について記載していきます。そもそもリフレクションとはCurlのクラスからメソッドやゲッターの情報を取得するAPIのことです。また、取得したメソッド等を実行することができます。
リフレクションを利用するためには、CURL.LANGUAGE.REFLECTIONというパッケージをインポートする必要があります。
{import * from CURL.LANGUAGE.REFLECTION} |
まず当機能を説明するにあたって以下のクラス(Foo)を例にとっていきたいと思います。
{curl 6.0 package} {package COM.CURLAP.TEST}
{define-class public open Foo
field private _a:String field private _b:int
{getter public {a}:String {return self._a} }
{getter public {b}:int {return self._b} }
{constructor public {default a:String, b:int } set self._a = a set self._b = b }
{method public open {display}:void
{dump self._a, self._b} } }
|
文字列からインスタンス作成
文字列のパッケージ名やクラス名からオブジェクトを生成する方法を下のソースコードをもとに説明していきます。
文字列(”COM.CURLAP.TEST”)から、Packageクラス(パッケージのクラスです。)のオブジェクトを生成するため、ComponentSelectorを利用します。この生成されたPackageオブジェクトから、その中に含まれるクラスやプロシージャを取得するため、get-memberメソッドを文字列のクラス名(”Foo”)を指定して実行します。get-memberメソッドはPackageMemberをかえします。
このPackageMemberのget-valueを利用し、ClassTypeクラスのオブジェクトを取得します。そのClassTypeからget-constructorを用いてConstructorを取得できますので、newメソッドを利用し、Fooクラスのオブジェクトを生成できます。
|| Package let p:Package = {import-package {ComponentSelector name = “COM.CURLAP.TEST”} } || PackageMember let m:#PackageMember = {p.get-member “Foo”}
|| ClassType let t:ClassType = {m.get-value}
|| Constructor let c:#Constructor = {t.get-constructor “default”}
|| オブジェクトの生成 {dump {c.new “xxxx”, 999}} |
オブジェクトからクラス名等の名前を取得
オブジェクトからクラス名やメソッド名、ゲッター・セッター名等を取得する方法を下のソースコードをもとにご説明します。
最初に、Fooオブジェクトを通常通り生成します。このFooオブジェクトのゲッターとメソッドの情報をリフレクションを利用し、取得することとします。
リフレクションの利用にあたってまずはFooオブジェクトのClassTypeオブジェクトをtype-ofマクロを用いて取得します。パッケージ名を取得するには、このClassTypeオブジェクトのpackage.nameアクセッサーを利用することで取得できます。次のゲッターやメソッドを取得するため、ClassType.get-membersメソッドを利用します。この際、ゲッターならClassMember.getter-filterをメソッドならClassMember.method-filterをキーワード引数のfilterに指定します。これによりすべてのゲッター名やメソッド名を取得することができます。
また、上記で取得した名前を元に、{ClassType.get-getter ゲッター名}でGetterオブジェクトを取得し、そのget-valueメソッドで値を主時できますし、{ClassType.get-method “メソッド名”}でMethodオブジェクトを取得し、invokeメソッドでメソッドを実行することができます。
let foo:Foo = {Foo “foo-foo-foo”, 1234} || ここからリフレクション! let t:ClassType = {type-of foo} asa ClassType {dump t.package.name} || パッケージ名の表示
|| getter {for m in {t.get-members filter = ClassMember.getter-filter} do def getter-name = m.name def getter:Getter = {t.get-getter getter-name} asa Getter {dump getter-name, {getter.get-value foo}} || ゲッター名とその値の表示 }
|| method {for m in {t.get-members search-superclasses? = false, filter = ClassMember.method-filter} do def method-name = m.name def method:Method = {t.get-method method-name} asa Method {dump method-name, {method.invoke foo}} || メソッド名とその値の表示 }
|
もちろんその他、セッターやプロシージャ等々の情報も取得し、実行することができます。
関連ドキュメント
リフレクション