4

Update: I answered my own question here:

Scanning classpath/modulepath in runtime in Java 9

--

[Old question -- obsolete:]

In the Java 9 module system, you can find system modules using

Set<ModuleReference> ms = ModuleFinder.ofSystem().findAll();

These ModuleReference objects can then be used to list the contents of each module, using:

for (ModuleReference m : ms) {
    System.out.println(m.descriptor().name());
    System.out.println(" " + m.descriptor().toNameAndVersion());
    System.out.println(" " + m.descriptor().packages());
    System.out.println(" " + m.descriptor().exports());
    Optional<URI> location = m.location();
    if (location.isPresent()) {
        System.out.println(" " + location.get()); // e.g. "jrt:/java.base"
    }
    m.open().list().forEach(s -> System.out.println("  " + s));
}

And to get the module of the current class, you can use

Module m = getClass().getModule();

but I can't seem to get a ModuleReference from this Module (so I can't list the contents of the module, other than the packages), and the non-system Modules are not listed by ModuleFinder.

Two questions:

  1. How do I enumerate the resources in non-system modules?
  2. How are non-module classpaths read in JRE 9? Am I just supposed to rely on the java.class.path system property? (The AppClassLoader#ucp field of type URLClassPath is not visible, and is locked down in JRE 9, so you can't get it by introspection either.)
Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
  • 2
    I guess the highlighted portion of your question shall be to get the URI(location/path) for modules? then I guess you are just bothered about the non-system modules, is that true? Since all the other attributes of your code are accessible via ModuleDescriptor which is an [entity of a Module](https://docs.oracle.com/javase/9/docs/api/java/lang/Module.html#getDescriptor--) itself. Also AFAIR this could possibly be a duplicate of a similar question. Would await for you to confirm the details. – Naman Dec 22 '17 at 05:44
  • 2
    Just taking a blind shot(without the details in the question), you might be interested in the [`ModuleLayer` of a `Module`](https://docs.oracle.com/javase/9/docs/api/java/lang/Module.html#getLayer--). If you look at the example in the link there, you can find configuration and the layer using the directory of modules via ModuleFinder. – Naman Dec 22 '17 at 05:53

1 Answers1

4

How about this:

Set<String> systemModuleNames = ModuleFinder
        .ofSystem()
        .findAll()
        .stream()
        .map(moduleRef -> moduleRef.descriptor().name())
        .collect(Collectors.toSet());

List<Module> nonSystemModules = ModuleLayer
        .boot()
        .modules()
        .stream()
        .filter(m -> !systemModuleNames.contains(m.getName()))
        .collect(Collectors.toList());

System.out.println(nonSystemModules);

Now when you have nonSystemModules, you can do anything you want with this list (e.g. get resources in each module).

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • 2
    Thanks @ZhekaKozlov. This unfortunately doesn't work for automatic (unnamed) modules, which it turns out is what I need to handle (specifically, automatic modules are not returned by `ModuleLayer.boot().modules()`). Do you know how to get a list of automatic modules? Re. question (2): What I'm referring to is the ability to add non-module classfiles to the classpath in Java 9. Are these always converted to automatic modules? I believe I read that the JRE still honors `java.class.path` and the `-cp` switch. For context, what I'm trying to accomplish is classpath scanning. – Luke Hutchison Dec 22 '17 at 12:23