6

Update: I answered my own question here:

Scanning classpath/modulepath in runtime in Java 9

--

[Old question -- obsolete:]

What is the correct way to get a ModuleReference given only a Module object in Java 9?

Consider these two methods of referring to java.base:

Module mod = ModuleLayer.boot().findModule("java.base").orElse(null);
ModuleReference modRef = ModuleFinder.ofSystem().find("java.base").orElse(null);

mod has a method Set<String> getPackages(), but you only get the names of the packages, you cannot list the resources in each package.

modRef has a method ModuleReader open(), and ModuleReader has a method Stream<String> list() that lists the resources in the module, which is what I need to do.

However, for automatic (and therefore unnamed) modules, produced by adding non-module jarfiles to the classpath, you cannot get a ModuleReference from ModuleFinder.ofSystem().find(String name) or ModuleFinder.ofSystem().findAll() -- you can only get the Module reference from getClass().getModule().

I cannot find any way to get a ModuleReference for automatic modules. I also cannot find a way to get a ModuleReference from a Module object, which means I am not able to list the resources in a Module if the module is automatic and/or unnamed.

Surely there must be a way to get a ModuleReference for a given (already-loaded) Module?

Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
  • Could you update the question with a reproducible sample of code and share the output of `configuration.modules()` that you get. – Naman Dec 28 '17 at 05:39

2 Answers2

3

First thing to clear out from the question is that the inference is incorrect in the sentence -

for automatic (and therefore unnamed) modules, produced by adding non-module jar files to the classpath

Automatic modules are named modules found on the module path. On the other hand, the unnamed module is a member of the module system which supports loading a type from the classpath whose package is not defined in any known(named) module.


The ClassLoader that was used to load the type itself can be used to get the Module(unnamed). I've tried explaining this in the answer to How many unnamed modules are created in Java 9? as well. To link to the precise documentation over the same that also answers with which class loader is the unnamed module associated?

Every class loader, it turns out, has its own unique unnamed module, which is returned by the new ClassLoader::getUnnamedModule method....

ClassLoader cl = getClass().getClassLoader();// returns the class loader for the class
Module yourClassLoaderUnnamedModule = cl.getUnnamedModule();

Moving further the document adds to getting the module of a type loaded form unnamed module::

.. type is considered to be in that loader’s unnamed module, i.e., the getModule method of the type’s Class object will return its loader’s unnamed module.

which eventually is equivalent to :

Module yourClassUnnamedModule = getClass().getModule(); // from the type itself

Primarily in terms of accessing resources of the unnamed module, though I agree there is no API currently visible to access the unnamed module's resources etc. Yet, since the type of the Class objects loaded via this module would always be from the classpath, one can either get all the resources of the classpath that is in use or the other way around, you can check if the resource in use is accessed from classpath or the module path. One way I could think of is to verify using the above two functionalities as :

yourClassLoaderUnnamedModule.equals(yourClassUnnamedModule)//true if resource is loaded via classpath
Naman
  • 27,789
  • 26
  • 218
  • 353
1

The module finder returned by ModuleFinder.ofSystem() is one that locates system modules, which are the modules built into the JRE environment running the application.

If the location of the automatic module on the file system is known, you could try retrieving a module finder using the directory, i.e. using ModuleFinder.of(path). Another way is to use the module layer’s configuration to resolve the module reference:

Optional<ResolvedModule> resolvedModule = ModuleLayer.boot().configuration().findModule(name);
Optional<ModuleReference> moduleReference = resolvedModule.map(ResolvedModule::reference);

To answer your general question about obtaining a module reference from only a Module, one way to do it:

Optional<ModuleReference> moduleReference
     = module.getLayer().configuration()
           .findModule(module.getName())
           .map(ResolvedModule::reference);

For an unnamed module, my guess is that you cannot retrieve a ModuleReference for it, but at least one can try calling configuration().modules() and see if they include an unnamed module.

M A
  • 71,713
  • 13
  • 134
  • 174
  • Thanks, @manouti. On your first point -- manually resolving modules by path within your code defeats the purpose of having a classpath / module path. And for the two code examples you gave, this requires a module to have a name -- and my point was that I am trying to do this for automatic modules. Automatic modules do not have a name (`getClass().getModule().getName()` returns null) if these modules come from the traditional classpath. They only have names (as I understand it) if you add them to the module path, not the classpath (then there is a module name produced from the jarfile name). – Luke Hutchison Dec 24 '17 at 22:41
  • An automatic module is actually a _named_ module; only the unnamed module does not have a name. So from what you're describing, `getClass().getModule().getName()` is returning null because the current class in which this code is running belongs to the unnamed module, and not as part of an automatic module. Adding non-module JARs to the classpath makes them part of the unnamed module, whereas an automatic module is added on the module path. – M A Dec 25 '17 at 14:10
  • I'm not sure in this case if there is a way to get a `ModuleReference`, but I would try calling [`boot().configuration().modules()`](https://docs.oracle.com/javase/9/docs/api/java/lang/module/Configuration.html#modules--) and see if they include an unnamed module. – M A Dec 25 '17 at 14:10
  • Yes, you're right, so I'm talking only about unnamed (classpath) modules then, not named automatic (module path) modules. No, unnamed modules are not returned by that call. There is more detail on why this is a problem in my email to jigsaw-dev here: http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-December/013439.html – Luke Hutchison Dec 25 '17 at 19:09