5

ここに投稿された質問に加えて、リフレクションを使用してパッケージ内のすべてのクラスを見つけることができますか? Reflections ライブラリを使用して、特定の型をサブクラス化するすべてのクラスを検索し始めました。リンクされたSOの質問への回答から、ソースコードは次のようになります。

Reflections ref = new Reflections(new ConfigurationBuilder()
    .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
    .setUrls(ClasspathHelper.forPackage("org.somepackage"))
    .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.somepackage"))));

ref.getSubtypesOf(Object.class);

しかし、しばらくこのコードを何も知らずに使用した後、このパッケージ内の別の型をサブクラス化するクラスしか検出されないことがわかりました。別のユーザー定義パッケージなど、外部で定義されたクラスをサブクラス化するクラスは見つかりません。

Reflections ライブラリを使用してこれを回避する方法がわかりません。スーパータイプに関係なく、パッケージを「org.somepackage」として宣言するすべてのクラスが必要です。何か助けはありますか?

4

3 に答える 3

6

私はRebound (Reflections ではなく) と呼ばれるライブラリを作成しました。このライブラリは、特定の型とパッケージ プレフィックスのサブクラスを検索します。プレフィックスを空に設定すると、クラスパスの下のすべてのクラスが検索されます。

import gigadot.exp.reflects.core.Processor;

Rebound r = new Rebound("");
Set<Class<? extends Processor>> classes = r.getSubClassesOf(Processor.class);

ただし、クラスパス内のすべてを検索すると処理が遅くなるため、注意が必要です。

このライブラリは Reflections よりもはるかに単純であり、希望どおりに動作しない可能性があります。バグレポートを提出したときの不満のためにこれを書きましたが、誰も問題を解決しようとしません。

于 2012-09-19T16:44:13.960 に答える
2

その理由は、

ref.getSubtypesOf(Object.class);

Object の直接のサブクラスのみを返します。スキャンしたパッケージからすべてのクラスを取得する場合は、次の手順を実行する必要があります。

Reflections ref = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner(), new TypeElementsScanner())
...
Set<String> typeSet = reflections.getStore().getStoreMap().get("TypeElementsScanner").keySet();
HashSet<Class<? extends Object>> classes = Sets.newHashSet(ReflectionUtils.forNames(typeSet, reflections
            .getConfiguration().getClassLoaders()));

これは少しハックに見えるかもしれませんが、これが私がこれまでに見つけた唯一の方法です。これが何をするのかを簡単に説明します。Reflections がスキャンを完了すると、すべての要素が多値マップに配置されます。貼り付けたコード例では、結果は次のキーを持つマップ内に配置されます。

SubTypesScanner, ResourcesScanner, TypeElementsScanner

ResourceScanner は、.class で終わるすべてのファイルを除外します。TypeElementsScanner は、クラスの名前とフィールドの値などを保持するキーを持つマップです。したがって、クラス名のみを取得する場合は、基本的にキー セットを取得し、後でそれをセットに変換します。クラス。SubTypesScanner もマップであり、すべてのスーパー クラス (オブジェクトとインターフェイスを含む) のキーと値 (これらのインターフェイス/クラスを実装/拡張するクラス) を持ちます。

キーセットを反復してすべての値を取得することにより、必要に応じて SubTypesScanner を使用することもできますが、特定のクラスがインターフェイスを実装している場合は、重複したエンティティを処理する必要があります (すべてのクラスがオブジェクトを拡張するため)。

それが役立つことを願っています。

于 2013-11-04T15:51:41.143 に答える
0

私の場合、このコードは外部 API のクラスをロードするのに問題なく動作しますが、'java.util' のような組み込みパッケージでは動作しない理由がわかりません。

Reflections reflections = new Reflections(new ConfigurationBuilder()
                .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
                .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[2])))
                .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.reflections"))));
于 2013-03-13T12:21:00.633 に答える