Java 9 如何在不知道 jar 文件的包名或文件系统路径的情况下列出所有资源

How to list all resources without know the package name or filesystem path for jar files in Java 9

在Java 7 & 8 我以前能做到

URLClassLoader urlLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
for (URL u : urlLoader.getURLs()) {
    System.out.println("*************** url=" + url);
}

但是在Java9上面给出了错误

java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClass
Loader

那么如何在不知道包前缀或 jar 文件的文件系统路径的情况下列出所有资源?

由于转向模块化架构,不再支持查找 class 路径的旧方法:

The application class loader is no longer an instance of URLClassLoader but, rather, of an internal class. It is the default loader for classes in modules that are neither Java SE nor JDK modules.

https://docs.oracle.com/javase/9/migrate/toc.htm

您可以尝试直接解析 class 路径 属性 或尝试使用 ModuleFinder 和朋友对模块做一些事情。

Java9 Release Note 指出:

The application class loader is no longer an instance of java.net.URLClassLoader (an implementation detail that was never specified in previous releases). Code that assumes that ClassLoader.getSytemClassLoader() returns a URLClassLoader object will need to be updated. Note that Java SE and the JDK do not provide an API for applications or libraries to dynamically augment the class path at run-time.

对于add to this from the mailing list,很少有资源查找方法,其中包括:

  • 命名模块中的class可以通过Class::getResourceAsStream method, which returns an InputStream. It can get a URL to one of its own resources via the Class::getResource方法读取自己的资源。这些方法不会定位其他命名模块中的资源。

  • ClassLoader::getResource* 方法不在任何位置定位资源 已命名 个模块。

  • Class and ClassLoader 中所有现有的资源查找方法都像今天一样对 class 路径 上的 资源进行工作。

  • 新的Module::getResourceAsStream方法即可 用于读取任何命名模块的资源,没有限制。

这些选择在 Jigsaw 的 resource encapsulation and readable artifact 要求之间提供了平衡。

我找到的最佳答案是为 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()));
     }
  }