Я искал какое-то время, и, похоже, существуют разные подходы, вот резюме:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader 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, который всегда будет ограничен уже загруженными классами, если вы не выполняете поиск по каталогам.