Вопрос-ответ

Can you find all classes in a package using reflection?

Можете ли вы найти все классы в пакете, используя отражение?

Возможно ли найти все классы или интерфейсы в данном пакете? (Быстрый просмотр, например, Package, может показаться, что нет.)

Переведено автоматически
Ответ 1

Из-за динамической природы загрузчиков классов это невозможно. Загрузчики классов не обязаны сообщать виртуальной машине, какие классы она может предоставить, вместо этого им просто передаются запросы для классов, и они должны возвращать класс или генерировать исключение.

Однако, если вы напишете свои собственные загрузчики классов или изучите пути к классам и их jars, найти эту информацию возможно. Однако это будет сделано с помощью операций файловой системы, а не отражения. Возможно, даже существуют библиотеки, которые помогут вам сделать это.

Если существуют классы, которые генерируются или доставляются удаленно, вы не сможете обнаружить эти классы.

Обычный метод заключается в том, чтобы вместо этого где-нибудь зарегистрировать классы, к которым вам нужен доступ, в файле или ссылаться на них в другом классе. Или просто используйте соглашение, когда дело доходит до именования.

Дополнение: Библиотека Reflections позволит вам искать классы в текущем пути к классам. Его можно использовать для получения всех классов в пакете:

 Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
Ответ 2

Вероятно, вам следует взглянуть на библиотеку Reflections с открытым исходным кодом. С ее помощью вы можете легко достичь желаемого.

Сначала настройте индекс отражений (это немного запутанно, поскольку поиск по всем классам по умолчанию отключен):

List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());

Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.your.package"))));

Затем вы можете запросить все объекты в данном пакете:

Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);
Ответ 3

Вы могли бы использовать этот метод1, который использует ClassLoader.

/**
* Scans all classes accessible from the context class loader which belong to the given package and subpackages.
*
* @param packageName The base package
* @return The classes
* @throws ClassNotFoundException
* @throws IOException
*/

private static Class[] getClasses(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
}

/**
* Recursive method used to find all classes in a given directory and subdirs.
*
* @param directory The base directory
* @param packageName The package name for classes found inside the base directory
* @return The classes
* @throws ClassNotFoundException
*/

private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}

__________

1 Изначально этот метод был взят из http://snippets.dzone.com/posts/show/4831, который был заархивирован Internet Archive, ссылка на который приведена ниже. Фрагмент также доступен по адресу https://dzone.com/articles/get-all-classes-within-package.

Ответ 4

Google Guava 14 включает новый класс ClassPath с тремя методами для поиска классов верхнего уровня:


  • getTopLevelClasses()

  • getTopLevelClasses(String packageName)

  • getTopLevelClassesRecursive(String packageName)

Смотрите ClassPath javadocs для получения дополнительной информации.

java reflection