web-dev-qa-db-ja.com

インターフェイスを実装するJavaクラスを見つける

少し前に、標準のJava機能を使用して特定のインターフェイスを実装したクラスを見つけるコードを見つけました。関数は非論理的な場所に隠されていましたが、パッケージ名が示すように他のクラスで使用できます。当時、私はそれを必要としなかったので、私はそれを忘れていましたが、今私はそうします、そして、私は再び機能を見つけることができないようです。これらの関数はどこにありますか?

編集:IDE関数などを探しているのではなく、Javaアプリケーション内で実行できるものを探しています。

121
Linor

しばらく前、私はあなたがしたいことなどをするためのパッケージをまとめました。 (私が書いていたユーティリティに必要でした)。 ASM ライブラリを使用します。リフレクションを使用できますが、ASMの方がパフォーマンスが向上しました。

Webサイトにあるオープンソースライブラリにパッケージを置きます。ライブラリは次のとおりです。 http://software.clapper.org/javautil/ 。 with ClassFinder クラスで開始したい。

私が書いたユーティリティは、私が今でも毎日使用しているRSSリーダーであるため、コードが実行される傾向があります。 ClassFinderを使用して、RSSリーダーでプラグインAPIをサポートしています。起動時に、特定のインターフェイスを実装するクラスを含むjarファイルとクラスファイルのディレクトリツリーを検索します。それはあなたが予想するよりもずっと速いです。

ライブラリはBSDライセンスであるため、コードに安全にバンドルできます。ソースが利用可能です。

それがあなたに役立つなら、自分で助けてください。

更新:Scalaを使用している場合は、 このライブラリ がScalaにより適していることがあります。

63
Brian Clapper

春はあなたのためにこれを行うことができます...

BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);

TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
s.addIncludeFilter(tf);
s.scan("package.you.want1", "package.you.want2");       
String[] beans = bdr.getBeanDefinitionNames();

N.B. TypeFilterは、正しい結果が必要な場合に重要です!代わりに、ここで除外フィルターを使用することもできます。

Scannerは、spring-context jar、spring-beansのレジストリ、type filterはspring-coreにあります。

50
Nick Robson

これを行うための reflections library が本当に好きです。

さまざまなタイプのスキャナー(getTypesAnnotatedWithgetSubTypesOfなど)が多数用意されており、独自のスキャナーを作成または拡張するのは非常に簡単です。

29
robertvoliva

あなたが話しているコードは ServiceLoader のような音です。これはJava 6で導入され、 Java 1. 以降に定義された機能をサポートします=またはそれ以前。パフォーマンス上の理由から、これは実行時にインターフェイス実装を見つけるための推奨されるアプローチです。古いバージョンのJavaでこれをサポートする必要がある場合、 my implementation が役立つことを願っています。

Javaの以前のバージョンではこの実装がいくつかありますが、コアAPIではなくSunパッケージにあります(これを行うImageIOの内部クラスがいくつかあると思います)。コードは単純なので、変更される可能性のある非標準のSunコードに依存するのではなく、独自の実装を提供することをお勧めします。

22
erickson

パッケージレベルの注釈

私はこの質問がかなり前にすでに回答されていることを知っていますが、この問題の別の解決策はパッケージレベルの注釈を使用することです。

JVM内のすべてのクラスを見つけるのは非常に困難ですが、実際にはパッケージ階層を簡単に参照できます。

Package[] ps = Package.getPackages();
for (Package p : ps) {
  MyAno a = p.getAnnotation(MyAno.class)
  // Recursively descend
}

次に、注釈にクラスの配列の引数を持たせるだけです。次に、特定のパッケージのpackage-info.JavaにMyAnoを配置します。

人々が興味を持っているが、おそらくアイデアを得る可能性が高い場合、私はより詳細(コード)を追加します。

MetaInf Service Loader

@ericksonの回答に追加するには、サービスローダーアプローチを使用することもできます。 Kohsukeには、サービスローダーアプローチに必要なMETA-INFを生成する素晴らしい方法があります。

http://weblogs.Java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html

13
Adam Gent

Extensible Component Scanner(extcos: http://sf.net/projects/extcos )を使用して、次のようなインターフェースを実装するすべてのクラスを検索することもできます。

Set<Class<? extends MyInterface>> classes = new HashSet<Class<? extends MyInterface>>();

ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
    @Override
    protected void query() {
        select().
        from("my.package1", "my.package2").
        andStore(thoseImplementing(MyInterface.class).into(classes)).
        returning(none());
    }
});

これは、ファイルシステム上のクラス、jar内、およびJBoss仮想ファイルシステム上のクラスに対しても機能します。さらに、スタンドアロンアプリケーション内だけでなく、任意のWebまたはアプリケーションコンテナー内でも機能するように設計されています。

8
Matthias Rothe

完全に一般的に、この機能は不可能です。 Java ClassLoaderメカニズムは、特定の名前(pacakgeを含む)のクラスを要求する機能のみを保証し、ClassLoaderはクラスを提供するか、そのクラスを知らないことを宣言できます。

クラスは、リモートサーバーからロードできます(頻繁にロードされます)。また、オンザフライで構築することもできます。 anyあなたが要求する名前に対して与えられたインターフェースを実装する有効なクラスを返すClassLoaderを書くことはまったく難しくありません。そのインターフェースを実装するクラスのリストは、長さが無限になります。

実際には、最も一般的なケースはURLClassLoaderで、ファイルシステムディレクトリとJARファイルのリストでクラスを検索します。したがって、必要なのはURLClassLoaderを取得し、それらのディレクトリとアーカイブを反復処理し、それらで見つかったクラスファイルごとに、対応するClassオブジェクトを要求し、そのgetInterfaces()メソッド。

6

明らかに、Class.isAssignableFrom()は、individualクラスが指定されたインターフェースを実装するかどうかを示します。そのため、問題はテストするクラスのリストを取得することです。

私の知る限り、Javaから直接クラスローダーに「潜在的にロードできるクラスのリスト」を要求する方法はありません。したがって、目に見えるjarファイルを繰り返し処理し、Class.forName()を呼び出してクラスをロードし、それをテストすることで、これを自分で行う必要があります。

ただし、実際にがロードされたものから特定のインターフェイスを実装するクラスを知りたい場合は、少し簡単です:

  • Java Instrumentation フレームワーク経由で、Instrumentation.getAllLoadedClasses()を呼び出すことができます
  • リフレクションを介して、特定のClassLoaderのClassLoader.classesフィールドを照会できます。

インストルメンテーションテクニックを使用する場合、(リンクで説明されているように)JVMの起動時に「エージェント」クラスが基本的に呼び出され、インストルメンテーションオブジェクトが渡されます。その時点で、おそらく静的フィールドに「後で保存」し、ロードしたクラスのリストを取得するためにメインアプリケーションコードに後で呼び出してもらいます。

5
Neil Coffey

実行中のプログラムでこれを実行するという観点から尋ねている場合は、Java.lang。*パッケージを調べる必要があります。 Classオブジェクトを取得する場合、isAssignableFromメソッドを使用して、それが別のクラスのインターフェースであるかどうかを確認できます。

これらを検索する方法で構築された単純なものはありません。Eclipseのようなツールはこの情報のインデックスを構築します。

テストするClassオブジェクトの特定のリストがない場合は、ClassLoaderオブジェクトを確認し、getPackages()メソッドを使用して独自のパッケージ階層イテレーターを作成できます。

ただし、これらのメソッドとクラスは非常に遅い可能性があるという警告です。

0
Matt Large