12

私は現在、Java で実装された特殊なインタープリター型プログラミング言語を使用しています。言語のごく一部として、Java に呼び出しを行う機能を追加したいと考えています。リフレクションのすべての核心に飛び込む前に、Java コードをリフレクティブに呼び出す「バックエンド」部分を実行するための一般的なライブラリを誰かが知っているかどうか疑問に思っていました。

つまり、文字列 (文法を定義) を解析して Java メソッド呼び出し (またはコンストラクター、またはフィールド アクセス) を表すデータ構造にし、そのデータ構造を、呼び出しを呼び出して結果を返すこのライブラリに渡します。特に、把握したくないすべてのエッジ ケースを既に処理できるようにしたいと考えています。

  • 引数のタイプに基づいて適切なメソッドを自動的に選択します (インテリジェントな Class.getDeclaredMethod() など)。
  • 配列と通常のオブジェクト参照の区別を処理する

JVM での動的言語の実装について少し調べてみましたが、これらは一般に、私が探しているよりもはるかに複雑であるか、特定の言語に対して高度に最適化されています。

もう 1 つのオプションは、私の文法を何らかの動的言語の文字列に変換し、それを Rhino などで呼び出すことですが、それは私が探しているよりも少しオーバーヘッドが大きくなります。

4

11 に答える 11

7

FEST Reflectionモジュールを試してください。これは、Java リフレクションを行う流暢な方法です。例えば:

 String name = method("get").withReturnType(String.class)
                         .withParameterTypes(int.class)
                         .in(names)
                         .invoke(8);
于 2008-12-13T21:00:01.503 に答える
7

あなた自身の答えへのコメントです。実際、beanutils は、一連のパラメーターを指定して「近似一致」を取得することをサポートしています。getMatchingAccessibleMethod()を参照してください。

BeanUtils は非常に強力で、クラスを検査するためのユーティリティ メソッドが多数あります。コンストラクターでも同じサポートが当然利用可能です。

于 2008-12-15T08:52:21.283 に答える
4

簡単にしたい場合は、Java でリフレクション API に簡単にアクセスできるように、jOORという簡単なライブラリを作成しました。巨大な API を構築することなく、最も重要なアクションをサポートします。jOOR コードの例を次に示します。

String world = 
on("java.lang.String") // Like Class.forName()
.create("Hello World") // Call the most specific matching constructor
.call("substring", 6)  // Call the most specific matching substring() method
.call("toString")      // Call toString()
.get()                 // Get the wrapped object, in this case a String
于 2011-12-29T19:16:02.033 に答える
2

Javaのスクリプトサポートを見てください; 私はそれがあなたの問題に取り組むのを助けると信じています。

于 2008-12-13T00:46:15.653 に答える
2

Apache Commons BeanUtilsをご覧ください

于 2008-12-13T19:59:36.507 に答える
1

これを死からよみがえらせるには:

invoke(Object object, String methodName, Object[] args) 

Apache Commons lang にはまさにその方法があります。 MethodUtils#invoke

于 2010-06-03T15:56:29.787 に答える
1

springs ReflectionUtils クラスも確認することを強く検討します。非常に強力な反射処理。

于 2010-01-21T06:10:07.587 に答える
1

hamcrestおよびlambdajと統合するライブラリ com.lexicalscope.fluent-reflection:fluent-reflection の作成を開始しました

次のようなコードを書くことができます。これは、クラス内のすべてのポスト コンストラクト アノテーション付きメソッドを呼び出します。

forEach(
   object(subject).methods(annotatedWith(PostConstruct.class)),
   ReflectedMethod.class).call();

ブログ投稿はこちら: http://www.lexicalscope.com/blog/category/software-projects/fluent-reflection/

ドキュメントはこちら: http://fluent-reflection.lexicalscope.com/

Maven Central から入手できます: http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

フィールドへのアクセスなど、現時点ではいくつかの基本的な機能が欠けていますが、メソッドに対しては機能します。私はたまにしか作業していないので、本当に機能が安定するポイント (1 年か 2 年など) に到達するには、おそらくしばらく時間がかかるでしょう。しかし、それは非常に高品質の標準に合わせて開発されており (私は願っています)、オープンソースであるため、必要なすべての機能があれば基本的にそのまま使用できます (必要に応じてコードを少し調整する必要があるかもしれません)。リリースされた新しいバージョンを使用するため)。現在、いくつかのプロダクションコードで使用しています。

非常に拡張できるように設計されているため、戦略をプラグインして、疎結合 (構成) スタイルで必要なメソッドを見つけることができます。したがって、必要な正確なメソッド検索戦略がない場合でも、簡単に追加できることを願っています。

于 2011-12-21T11:40:14.297 に答える
0

私は結局アレックスの提案に行きました。BeanUtils は Bean に大いに役立ちますが、Bean だけで作業したくありません。FEST は非常に優れているようで、さらに調査するためにブックマークしましたが、BeanUtils と同様に、ここで難しい問題であると私が考えるものを解決するようには見えません。つまり、メソッド名と引数のリストを指定して、引数に最も「適合する」メソッドを選択します。メソッドが float を取り、double を持っている場合、署名が正確に一致しないためにそのメソッドを拒否しないように十分にスマートにする必要があります。

明らかに、JVM 上に構築されたスクリプト言語はこの問題を解決しますが、言語固有の最適化により、必要以上に複雑な方法になります。したがって、これは小規模で実験的な機能であるため、Java 1.6 のスクリプト エンジン サポート (特に JavaScript) を使用する迅速な解決策を選択しました。基本的な考え方は次のとおりです。

private ScriptEngine engine = ... initialize with JavaScript engine ...

private Object invoke(Object object, String methodName, Object[] args) 
   throws RhsFunctionException
{
   // build up "o.method(arg0, arg1, arg2, ...)"
   StringBuilder exp = new StringBuilder("o." + methodName);
   engine.put("o", object);
   buildArgs(arguments, exp);

   try {
      return engine.eval(exp.toString());
   }
   catch (ScriptException e) {
      throw new RhsFunctionException(e.getMessage(), e);
   }
}

private void buildArgs(Object[] args, StringBuilder exp)
{
   // Use bindings to avoid having to escape arguments
   exp.append('(');
   int i = 0;
   for(Symbol arg : args) {
         String argName = "arg" + i;
         engine.put(argName, arg);
         if(i != 0) {
            exp.append(',');
         }
         exp.append(argName);
         ++i;
   }
   exp.append(')');
}

明らかにそれにはもう少し多くのことがありますが、これが基本的な考え方です。文字列を構築して評価するのはあまり好きではありませんが、Alex が提案したバインディングを使用することで、エスケープに関する落とし穴のほとんどを回避できます。さらに、必要に応じて「実際の」実装と交換できる、クリーンでシンプルなインターフェイスがあります。

フィードバックや代替ソリューションは大歓迎です。

于 2008-12-13T21:41:58.017 に答える
0

このスレッドを読んだ後、私はこのコードを作成し、オープンソース化しました。役に立つかもしれません。

https://github.com/yclian/Reflects.java/blob/master/src/test/java/my/jug/reflects/ReflectsTest.java

Guava にインスパイアされているため、Predicate好きなメソッドをフィルタリングするために使用できます。

于 2011-11-07T06:36:39.247 に答える
0

リフレクションプロジェクトがあります。これは、上記の他のリゾートと比較して Java 8 をサポートする最新のユーティリティ リフレクション ライブラリであり、最終的に 2020 年 3 月の時点でいくつかの高度なリフレクション アクションを実行するための最良の方法であると考えています。

それは読みます:

リリースされた org.reflections:reflections:0.9.12 - Java 8 のサポート付き
...
Reflections ライブラリは、Maven Central から毎月 250 万回以上ダウンロードされており、何千ものプロジェクトやライブラリで使用されています。プル リクエストのレビューとリリースの管理を手伝ってくれるメンテナーを探しています。ぜひご連絡ください。
...
Reflections はクラスパスをスキャンし、メタデータのインデックスを作成し、実行時にクエリを実行できるようにし、プロジェクト内の多くのモジュールの情報を保存および収集できます。

Java Standard Reflection と組み合わせて使用​​すると、すべてのニーズを満たすことができます。

于 2020-05-11T16:14:38.277 に答える