リフレクションなどでそれを行うことはできますか?
私はしばらく探していましたが、異なるアプローチがあるようです、ここに要約があります:
反射依存関係の追加を気にしないのであれば、ライブラリはかなり人気があります。次のようになります。
_Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
_
ServiceLoader(エリクソンの回答による)そして次のようになります:
_ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
_
これが機能するには、Pet
をServiceProviderInterface(SPI)として定義し、その実装を宣言する必要があることに注意してください。 _resources/META-INF/services
_という名前のファイルを_examples.reflections.Pet
_という名前で作成し、その中にPet
のすべての実装を宣言することにより、それを行います。
_examples.reflections.Dog
examples.reflections.Cat
_
パッケージレベルの注釈。以下に例を示します。
_Package[] packages = Package.getPackages();
for (Package p : packages) {
MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
if (annotation != null) {
Class<?>[] implementations = annotation.implementationsOfPet();
for (Class<?> impl : implementations) {
System.out.println(impl.getSimpleName());
}
}
}
_
および注釈定義:
_@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
_
また、そのパッケージ内の_package-info.Java
_という名前のファイルでパッケージレベルのアノテーションを宣言する必要があります。サンプルの内容は次のとおりです。
_@MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
_
その時点でClassLoaderに認識されているパッケージのみがPackage.getPackages()
の呼び出しによってロードされることに注意してください。
さらに、ディレクトリベースの検索を行わない限り、URLClassLoaderに基づく他のアプローチがあり、常に既にロードされているクラスに制限されます。
エリクソンが言ったことですが、それでもやりたい場合は Reflections を見てください。彼らのページから:
Reflectionsを使用すると、次のメタデータを照会できます。
- あるタイプのすべてのサブタイプを取得する
- 何らかの注釈が付けられたすべてのタイプを取得する
- 一致する注釈パラメーターを含む、何らかの注釈が付けられたすべてのタイプを取得します
- いくつかの注釈が付いたすべてのメソッドを取得します
一般に、これを行うには費用がかかります。リフレクションを使用するには、クラスをロードする必要があります。クラスパスで利用可能なすべてのクラスをロードする場合、時間がかかり、メモリがかかるため、お勧めしません。
これを避けたい場合は、リフレクションではなく、より効率的に動作する独自のクラスファイルパーサーを実装する必要があります。このアプローチには、バイトコードエンジニアリングライブラリが役立ちます。
サービスプロバイダーメカニズム は、プラグ可能なサービスの実装を列挙する従来の手段です。 ServiceLoader
in Java 6を使用するか、以前のバージョンで独自に実装します。別の回答で 例 を提供しました。 。
Springには、これを達成するための非常に簡単な方法があります。
public interface ITask {
void doStuff();
}
@Component
public class MyTask implements ITask {
public void doStuff(){}
}
その後、タイプITask
のリストを自動配線すると、Springがすべての実装をリストに追加します。
@Service
public class TaskService {
@Autowired
private List<ITask> tasks;
}
エリクソンが言ったことは最高です。関連する質問と回答のスレッドを次に示します- http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
Apache BCELライブラリを使用すると、クラスをロードせずに読み取ることができます。検証手順をスキップできるため、より高速になると思います。クラスローダーを使用してすべてのクラスをロードする際のもう1つの問題は、メモリへの多大な影響を被るだけでなく、おそらく望まない静的コードブロックを誤って実行することです。
Apache BCELライブラリリンク- http://jakarta.Apache.org/bcel/
はい、最初のステップは、気にしたクラスを「すべて」識別することです。この情報が既にある場合は、それらの各情報を列挙し、instanceofを使用して関係を検証できます。関連記事はこちら http://www.javaworld.com/javaworld/javatips/jw-javatip113.html
私は同じ問題に遭遇しました。私の解決策は、リフレクションを使用してObjectFactoryクラスのすべてのメソッドを調べ、バインドされたPOJOのいずれかのインスタンスを返すcreateXXX()メソッドではないメソッドを排除することでした。そのように検出された各クラスはClass []配列に追加され、JAXBContextインスタンス化呼び出しに渡されます。これはうまく機能し、ObjectFactoryクラスをロードするだけでよく、それはとにかく必要でした。 ObjectFactoryクラスを維持する必要があるのは、手作業(POJOで始めてschemagenを使用したため)で実行するか、xjcで必要に応じて生成できるタスクです。いずれにせよ、パフォーマンスが高く、シンプルで効果的です。
また、IDEプラグイン(あなたがやろうとしていることは比較的一般的です)を書いている場合、通常、IDEはより効率的な方法を提供しますユーザーコードの現在の状態のクラス階層にアクセスします。
@ kaybee99の答えの新しいバージョンですが、ユーザーが尋ねたものを返します:実装...
Springには、これを達成するための非常に簡単な方法があります。
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
@Component
public class MyTask implements ITask {
public void doStuff(){}
}
その後、タイプITask
のリストを自動配線すると、Springがすべての実装をリストに追加します。
@Service
public class TaskService {
@Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}
ClassGraph を使用すると、非常に簡単です。
my.package.MyInterface
の実装を見つけるためのGroovyコード:
@Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.className
ClassGraph を試してください。 (免責事項、私は著者です)。 ClassGraphは、実行時またはビルド時に特定のインターフェイスを実装するクラスのスキャンをサポートしますが、さらに多くのクラスのスキャンもサポートします。 ClassGraphは、メモリ内、クラスパス上のすべてのクラス、またはホワイトリストに登録されたパッケージ内のクラスについて、クラスグラフ全体(すべてのクラス、注釈、メソッド、メソッドパラメーター、フィールド)の抽象表現を構築できますが、そのクラスグラフをクエリできますあなたが欲しい。 ClassGraphは、他のスキャナーよりも クラスパス指定メカニズムとクラスローダー をサポートしており、新しいJPMSモジュールシステムともシームレスに動作します。そのため、ClassGraphに基づいてコードを作成すると、コードの移植性が最大限になります。 ここのAPIを参照してください。