Ответ 1
Вы не можете. Классы могут проходить через множество различных загрузчиков классов, включая удаленные.
Как мне получить все классы внутри пакета?
Вы не можете. Классы могут проходить через множество различных загрузчиков классов, включая удаленные.
Здесь более полный способ решить эту проблему для банок, основанный на идее, опубликованной JG.
/**
* Scans all classloaders for the current thread for loaded jars, and then scans
* each jar for the package name in question, listing all classes directly under
* the package name in question. Assumes directory structure in jar file and class
* package naming follow java conventions (i.e. com.example.test.MyTest would be in
* /com/example/test/MyTest.class)
*/
public Collection<Class> getClassesForPackage(String packageName) throws Exception {
String packagePath = packageName.replace(".", "/");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<URL> jarUrls = new HashSet<URL>();
while (classLoader != null) {
if (classLoader instanceof URLClassLoader)
for (URL url : ((URLClassLoader) classLoader).getURLs())
if (url.getFile().endsWith(".jar") // may want better way to detect jar files
jarUrls.add(url);
classLoader = classLoader.getParent();
}
Set<Class> classes = new HashSet<Class>();
for (URL url : jarUrls) {
JarInputStream stream = new JarInputStream(url.openStream()); // may want better way to open url connections
JarEntry entry = stream.getNextJarEntry();
while (entry != null) {
String name = entry.getName();
int i = name.lastIndexOf("/");
if (i > 0 && name.endsWith(".class") && name.substring(0, i).equals(packagePath))
classes.add(Class.forName(name.substring(0, name.length() - 6).replace("/", ".")));
entry = stream.getNextJarEntry();
}
stream.close();
}
return classes;
}
Здесь есть фрагмент , который делает именно то, что вы хотите, предполагая, что классы можно найти локально:
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()]);
}
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;
}
Нет глобального способа сделать это. При этом, если вы знаете, откуда идут ваши классы, вы можете перейти в каталог файла jar или файловой системы.
Java не имеет обнаружения.
В большинстве продуктов, которые могут добавлять (открывать) новые классы, есть текстовый файл, описывающий "Расширения программы" или конкретный каталог, в котором вы можете разместить классы или банки, которые используют трюк типа @JG. (Это то, что делает eclipse и рекомендуется для любого решения, где пользователь может добавить новый модуль вручную)
В приведенных выше ответах описываются требуемые функции. Однако более подробную информацию по этому вопросу можно найти здесь и здесь.