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