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

Viewed 1752

in Java 7 & 8 I use to be able to do

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

But in Java 9 the above gives an error

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

So how do I list all resources without knowing the package prefix or the filesystem path of the jar files?

3 Answers

The Java9 Release Note states this:

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.

To add to this from the mailing list there are few resource-lookup methods which include ways such as :

  • A class in a named module can read its own resources via the Class::getResourceAsStream method, which returns an InputStream. It can get a URL to one of its own resources via the Class::getResource method. These methods will not locate resources in other named modules.

  • The ClassLoader::getResource* methods do not locate resources in any named modules.

  • All existing resource-lookup methods in Class and ClassLoader work as they do today for resources on the classpath.

  • The new Module::getResourceAsStream method can be used to read the resources of any named module, without restriction.

These choices provides a balance between both resource encapsulation and readable artifact requirements on Jigsaw.

Best answer I found is to provide an argument to getResources, of course means you know prefix of the path the resources are located

  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()));
     }
  }

Because of the move to modular architecture, the old approach for looking up class paths is no longer supported:

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

You can try to parse the classpath property directly or try to do something with modules using ModuleFinder and friends.

Related