reflection性地获取项目中的所有包?

我怎样才能反思地获得项目中的所有包? 我从Package.getPackages()开始,但只获得了与当前包关联的所有包。 有没有办法做到这一点?

@ PhilippWendler的评论让我想到了一种完成我需要的方法。 我稍微调整了一下这个方法,使其递归。

/** * Recursively fetches a list of all the classes in a given * directory (and sub-directories) that have the @UnitTestable * annotation. * @param packageName The top level package to search. * @param loader The class loader to use. May be null; we'll * just grab the current threads. * @return The list of all @UnitTestable classes. */ public List> getTestableClasses(String packageName, ClassLoader loader) { // State what package we are exploring System.out.println("Exploring package: " + packageName); // Create the list that will hold the testable classes List> ret = new ArrayList>(); // Create the list of immediately accessible directories List directories = new ArrayList(); // If we don't have a class loader, get one. if (loader == null) loader = Thread.currentThread().getContextClassLoader(); // Convert the package path to file path String path = packageName.replace('.', '/'); // Try to get all of nested directories. try { // Get all of the resources for the given path Enumeration res = loader.getResources(path); // While we have directories to look at, recursively // get all their classes. while (res.hasMoreElements()) { // Get the file path the the directory String dirPath = URLDecoder.decode(res.nextElement() .getPath(), "UTF-8"); // Make a file handler for easy managing File dir = new File(dirPath); // Check every file in the directory, if it's a // directory, recursively add its viable files for (File file : dir.listFiles()) { if (file.isDirectory()) ret.addAll(getTestableClasses(packageName + '.' + file.getName(), loader)); } } } catch (IOException e) { // We failed to get any nested directories. State // so and continue; this directory may still have // some UnitTestable classes. System.out.println("Failed to load resources for [" + packageName + ']'); } // We need access to our directory, so we can pull // all the classes. URL tmp = loader.getResource(path); System.out.println(tmp); if (tmp == null) return ret; File currDir = new File(tmp.getPath()); // Now we iterate through all of the classes we find for (String classFile : currDir.list()) { // Ensure that we only find class files; can't load gif's! if (classFile.endsWith(".class")) { // Attempt to load the class or state the issue try { // Try loading the class Class add = Class.forName(packageName + '.' + classFile.substring(0, classFile.length() - 6)); // If the class has the correct annotation, add it if (add.isAnnotationPresent(UnitTestable.class)) ret.add(add); else System.out.println(add.getName() + " is not a UnitTestable class"); } catch (NoClassDefFoundError e) { // The class loader could not load the class System.out.println("We have found class [" + classFile + "], and couldn't load it."); } catch (ClassNotFoundException e) { // We couldn't even find the damn class System.out.println("We could not find class [" + classFile + ']'); } } } return ret; } 

它可能但是很棘手且昂贵,因为你需要自己走类路径。 以下是TestNG的工作方式,您可以为自己提取重要部分:

https://github.com/cbeust/testng/blob/master/src/main/java/org/testng/internal/PackageUtils.java

此方法仅打印所有包(必须首先给出根“packageName”)。

它源自上面。

 package devTools; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; public class DevToolUtil { /** * Method prints all packages (at least a root "packageName" has to be given first). * * @see http://stackoverflow.com/questions/9316726/reflectively-get-all-packages-in-a-project * @since 2016-12-05 * @param packageName * @param loader * @return List of classes. */ public List> getTestableClasses(final String packageName, ClassLoader loader) { System.out.println("Exploring package: " + packageName); final List> ret = new ArrayList>(); if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); } final String path = packageName.replace('.', '/'); try { final Enumeration res = loader.getResources(path); while (res.hasMoreElements()) { final String dirPath = URLDecoder.decode(res.nextElement().getPath(), "UTF-8"); final File dir = new File(dirPath); if (dir.listFiles() != null) { for (final File file : dir.listFiles()) { if (file.isDirectory()) { final String packageNameAndFile = packageName + '.' + file.getName(); ret.addAll(getTestableClasses(packageNameAndFile, loader)); } } } } } catch (final IOException e) { System.out.println("Failed to load resources for [" + packageName + ']'); } return ret; } public static void main(final String[] args) { new DevToolUtil().getTestableClasses("at", null); } } 

可能是偏离主题(因为它不完全是java“reflection”)…但是,以下解决方案如何:

可以将Java包视为文件夹(或Linux \ UNIX上的目录)。 假设您有一个root包并且其绝对路径已知,您可以使用以下批处理作为基础递归打印所有包含* .java或* .class文件的子文件夹:

 @echo off rem List all the subfolders under current dir FOR /R "." %%G in (.) DO ( Pushd %%G Echo now in %%G Popd ) Echo "back home" 

您可以在java中包装此批处理,或者如果您在Linux上运行,Unix会在某些shell脚本中重写它。

祝好运!

阿维亚德。