これを行うために groovy の invokeMethod を使用することを望んでいましたが、Java から Groovy を呼び出すと、invokeMethod は呼び出されませんが、それ以外の場合は完全に機能することがわかりました。
Groovy クラスを Java クラス (編集できない) に送信するケースがあります。Groovy クラスには注釈が付けられ、Java クラスは注釈をスキャンし、注釈付きのメソッドをそのイベントのリスナーとして保存します。
イベントが発行されたら、イベント オブジェクトから情報を取得し、それを使用してデータを取得し、そのデータをスクリプトのイベント ハンドラーに挿入します (そのメソッド内の注釈付き変数を介して)。
私が制御できることは、スクリプトをインスタンス化し、それらの基本クラスを設定し、それらを他のシステムに渡して登録することです。スクリプトは他の人によって書かれます - 私はスクリプトのデザインを制御できますが、私の目標はシンプルさです。
おそらくアダプター クラスを作成できますが、現在のように注釈を使用する代わりに、これらすべてのメソッドを手動で登録する必要があるため、非常に困難で壊れやすいようです。リッスンするさまざまなイベントがたくさんあります。
私が考えていないグルーヴィーなトリックがあるかどうか疑問に思っています。私はグルーヴィーなメタプログラミングにはまだかなり慣れていません。おそらく、アダプター クラスを自動的に作成する方法や、スクリプトをコンパイルするときに、メソッドを実際のメソッドを呼び出す前にコードに転送する転送メソッドに置き換える方法があります。
要求されたソース コード:
ソースコード - 見てみましょう、このプロセスはいくつかのクラスに分散しています...
これは、ScriptBase を使用して Groovy Class Loader をセットアップする方法です
cconfig.setScriptBaseClass("tv.kress.bill.minecraft.ezplugin.ScriptBase");
GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader(), cconfig);
次に、それを Groovy Scripting Engine に渡します (ここでは一部省略しています)。
gse = new GroovyScriptEngine(cpString, gcl);
次に、スクリプトをインスタンス化します
scriptClass = gse.loadScriptByName(file.getAbsolutePath());
instance = (GroovyObject) scriptClass.newInstance();
次に、「定型化された」Java ライブラリが注釈をスキャンする必要がある Java クラスを識別するために使用するマーカー インターフェイスである「リスナー」である場合、注釈付きのメソッドを登録できるように、それをそのクラスに渡します (行「インスタンス」は「スクリプト」になりましたが、同じオブジェクトです:
if (script instanceof Listener)
pm.registerEvents((Listener) script, this);
スクリプト自体の興味深い部分は次のようになります。
@EventHandler
public void userEvent(UserInteractEvent event) {
追加したいのは、userEvent 内に、次のような注釈付きローカル変数を追加する機能です。
@Persist int persistedPerUserData // Or @PersistPerUser? or @Persist(User=true)?
userEvent が呼び出される直前にインターセプトできるようにします。UserInteractionEvent からユーザー名を取得し、それをスクリプト、変数、およびメソッド名と組み合わせて、"MyScript:UserEvent:Bill:persistedPerUserData" のような一意の署名を取得し、それを使用して、persistedPerUserData に配置できる int を取得します。
後でメソッドが返された後、persistedPerUserData から値を取得し、それを "MyScript:UserEvent:Bill:persistedPerUserData" に戻します (現在はハッシュですが、最終的にはデータベースにする予定です)。
このように、スクリプトはさまざまなユーザーを扱っているという事実を考慮する必要はありません。変数のセットが 1 つあれば、すべての永続性が機能します。
これが機能するイベントは他にもありますが、それらはすべて同じイベントを拡張し、そのルートイベントには「ユーザー」フィールドがあると思います。
編集:試してはいけないもう1つのこととして、次のようにProxyMetaClass/インターセプターを使用しようとしました:
// Attempt (and fail) to intercept calls to an instance of clazz
class Slicer {
public static Object slice(Class clazz) {
Object instance;
def proxy = ProxyMetaClass.getInstance(clazz);
proxy.interceptor = new MyInterceptor();
proxy.use {
instance = clazz.newInstance();
}
return instance;
}
}
同じ結果で、groovy クラスからのすべての呼び出しは正常に計測されましたが、Java からの呼び出しはインターセプトされませんでした。ふりだしに戻る。これが、アスペクトがバイトコード操作を使用する理由だと思います。