Missing module discovery functionality in Jigsaw/JPMS API?

Alan Bateman Alan.Bateman at oracle.com
Thu Dec 28 08:40:22 UTC 2017


On 24/12/2017 23:31, Luke Hutchison wrote:
> I am the author of Fast Classpath Scanner
> <https://github.com/lukehutch/fast-classpath-scanner/>. I am trying to
> extend this library to work with JDK 9, and I'm running into a lot of
> apparent shortcomings of the JPMS API.
If you are scanning the class path today then you should find it works 
the same in JDK 9. The main thing that you will need to add support for 
is Multi-Release JARs (details in JEP 238, the JAR file spec, and the 
JarFile API).

Most of your questions are about enumerating the resources in unnamed 
modules (meaning the class path) rather than resources in named modules. 
If you are scanning the class path today then you are already scanning 
the resources in the unnamed module of the application class loader. The 
java.lang.module APIs that are attempting to lean on are used for module 
resolution that creating configurations of named modules (which are then 
instantiated in the Java virtual machine as module layers). This should 
become clear once you spend a bit more time getting familiar with the 
concepts.

For scanning then it might be useful to work through an example of 
something looking to scan a set of observable modules and selecting the 
root modules to resolve. This is where you might use the ModuleFinder 
API, maybe combining it with your existing class path scanner.

Post-resolution examples may also be interesting. Here you might find it 
useful to work through examples that need to locate resources in named 
modules that are already loaded and instantiated.

>
> These are the main issues I have come across so far:
>
> (1) Automatic modules from the legacy classpath cannot be found using
> ModuleFinder.ofSystem() (because they are not system modules), or using
> ModuleLayer.boot().modules() (because this list does not include unnamed
> modules).
Automatic modules are named modules. They are deployed on the module 
path, not the class path.

>
> (2) I would guess then that unnamed modules are in their own layer, but the
> Layer API only allows you to look at parent layers, not child layers -- so
> it is not even possible to enumerate all layers in the system. Why is there
> no call for enumerating all layers, and/or for reading child layers?
Unnamed modules are not in a module layer.

Module layers beyond the boot layer is an advanced topic. Once you are 
further along then it may make sense to extend your API to support 
scanning using a ModuleLayer as context.

>
> (3) ModuleLayer.boot().configuration().findModule(name) cannot find unnamed
> automatic modules either, because name cannot be null (and using the empty
> string doesn't return unnamed layers).
As (1), automatic modules are named modules. As (2), a module layer 
contains only named modules.


>
> (4) From within a class in a traditional (non-module) jar on the classpath,
> using getClass().getModule(), does return a Module reference for the
> unnamed module. However, there is no API that I can find for getting a
> ModuleReference from a Module object, if the module is unnamed. For
> example, the following should work if the module is named, but does not
> work if the module is unnamed:
>
>      Optional<ModuleReference> moduleReference =
>          module
>              .getLayer()
>              .configuration()
>              .findModule(module.getName())
>              .map(ResolvedModule::reference);
This is expected, as unnamed modules are not in a layer or configuration.

Note that there is no guarantee that a named module is in a module layer 
(Module::getLayer may return null). This is a corner case for where you 
are now of course.

> (5) ModuleFinder.of(path) would find the module, if the path were known.
> But there is no way to get the path from the Module reference obtained
> using getClass().getModule() -- you need a ModuleReference object to get
> the URI of the module, and you cannot get a ModuleReference, as described
> in (4) above.
The main thing to understand is that Module/ModuleLayer is the 
loaded/instantiated modules. The types you see in the java.lang.module 
package (including ModuleReference) is the model world. When a Module is 
in a module layer then you use the ModuleLayer::configuration method to 
go back to the Configuration.


>
> (6) Having to specify a path when calling ModuleFinder.of(), as shown in
> (5), defeats the purpose of having a classpath and/or module path that is
> specified outside of program code. I imagine it is primarily useful for
> dynamic loading of modules, but what I'm interested in is the static
> classpath / module path.
For the static / out-of-the-box case, the value of the java.class.path 
property is the class path (I suspect you are already using that).

The value of the jdk.module.path property (documented in 
System.getProperties) is the application module path.

In JEP 261 you'll find all the details in the module path section on the 
search order, which will be important if your extended APIs is used to 
scan observable modules.


> It seems like there are lots of obvious omissions in the API, from an
> enumeration / scanning point of view. Or am I missing something?
>
I think you've found some of the APIs, it's mostly just getting the 
concepts right to use them effectively.

-Alan.


More information about the jigsaw-dev mailing list