在Java 7&8我过去可以做
URLClassLoader urlLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
for (URL u : urlLoader.getURLs()) {
System.out.println("*************** url=" + url);
}
但在Java 9中,上面给出了一个错误
java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClass
Loader
那么,在不知道jar文件的包前缀或文件系统路径的情况下,如何列出所有资源呢?
Java9发行说明中指出:
应用程序类加载器不再是的实例
java.net.URLClassLoader
(从未在以前的版本中指定)。假设ClassLoader.getSytemClassLoader()
返回一个URLClassLoader
对象需要更新。请注意,Java SE和JDK不提供API,用于动态扩充类的应用程序或库路径。
要从邮件列表中添加到这一点,有一些资源查找方法,包括:
-
命名模块中的类可以通过返回
InputStream
的Class::getResourceAsStream
方法读取自己的资源。它可以通过Class::getResource
方法获得一个指向自己资源的URL。这些方法将不会在其他命名模块中查找资源。 -
ClassLoader::getResource*
方法在任何命名为模块。 -
Class
和ClassLoader
中所有现有的资源查找方法的工作方式与现在对类路径上的资源的工作方式相同。 -
新的
Module::getResourceAsStream
方法可以用于读取任何命名模块的资源,不受限制。
这些选择在Jigsaw上提供了资源封装和可读工件需求之间的平衡。
我找到的最好答案是为getResources提供一个参数,当然这意味着你知道资源所在路径的前缀
ArrayList<URL> resources = new ArrayList<URL>();
ClassLoader urlLoader = ClassLoader.getSystemClassLoader();
Enumeration<URL> eU = urlLoader.getResources("com");
while (eU.hasMoreElements()) {
URL u = eU.nextElement();
JarFile jarFile = new JarFile(u.getFile().replace("file:/", "").replaceAll("!.*$", ""));
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
JarEntry jarEntry = e.nextElement();
resources.add(urlLoader.getResource(jarEntry.getName()));
}
}
由于转向模块化架构,不再支持查找类路径的旧方法:
应用程序类加载器不再是的实例URLClassLoader,而是一个内部类。它是默认值既不是Java SE也不是JDK的模块中的类的加载器模块。
https://docs.oracle.com/javase/9/migrate/toc.htm
您可以尝试直接解析classpath属性,也可以尝试使用ModuleFinder
和friends对模块执行某些操作。