Automodules

David M. Lloyd david.lloyd at redhat.com
Mon Feb 13 15:59:44 UTC 2017


On 02/11/2017 10:18 AM, Robert Scholte wrote:
> There are clearly 2 kinds of jars in play here: dependencies and
> end-products.
>
> To have a reliable end-product you want to specify *every* requirement
> and in this case it doesn't matter that a dependency has no official
> module name, as long as you can specify and refer to it as a requirement.
>
> To have a reliable dependency you can only depend on named modules. Up
> until now it is required to specify all requirements or do some command
> line argument magic to compile or run such project.
>
> What I would like to achieve is to have a situation where end-products
> can never be used as a dependency, because that would allow auto
> modules, which makes it again unreliable as dependency.

We accomplished exactly these goals in jboss-modules, simply by having 
multiple "worlds": The module world itself (of course), and separated 
worlds for the modularized class path or -jar command line.

In the raw class path situation, we create a single module for the 
entire class path.  This is essentially an "unnamed" blob, which can 
consume available modules but cannot in turn be consumed by them.  This 
allows a first step into the module world by allowing (over time) the 
user to move modules from the class path into the module space as their 
dependencies can be correctly and specifically analyzed (in other words, 
it's one step from sloppy class path to constrained/clean module). 
Classpath JARs could also be separated into modules which have a mutual 
dependency mesh (assuming that circular dependencies are allowed), 
allowing for a better diagnostic identity than just "classpath" (for 
example).

In the -jar situation, we create a module per JAR using the JAR's 
Class-Path MANIFEST.MF header as the linking mechanism.  In the 
container we also support the old extensions mechanism (which it turns 
out is actually a pretty good basic module system in its own right).  In 
this way, JARs are isolated from one another, consuming only what is 
explicitly declared.  In the Java EE container, these dependencies are 
usually transitive due to some unfortunate specification language, but 
on the command-line they are not, which further improves isolation.  In 
this case as well JARs can depend on modules but not vice-versa. 
Circularity is also historically allowed in this situation.

I have found these mechanisms to be more than adequate for providing an 
easy on ramp for modularization, and neither one requires module name 
fudging; in fact, mangling of names is harmful since it takes the 
intuitive "my-project-1.3.3.jar" that would appear in diagnostics, which 
can be copied and pasted into a "find" command for example, and turns it 
into something rather unintuitive.  Having a modular classpath in fact 
is the easiest possible "small" step because it allows code to run under 
the new module accessibility and (service) loading rules without 
otherwise affecting class loading behavior in any way.

This is why I'm frustrated with automatic modules: they just don't seem 
necessary, and have several proven problems which also seems to make 
them insufficient.

> Specifying a dependency is done by referring to the name of a module.
> So what if we say that a end-product doesn't have a name anymore or that
> it is not a module anymore. In that case it cannot be used as dependency
> AND we could allow automodules in such case.
>
> In case of a dependency or named module you can only refer to other
> named modules. All other required jars should be picked up from the
> classpath, preferably by default.
>
> This is just a start, but would probably match most requirements from
> both camps.
>
> So an example of the end-product jar:
>
> final myapp { // 'module' replaced with 'final'
>     requires mylib;             // a named module, assume part of Maven
> multimodule project
>     requires java.base;         // a named module, part of Java
>     requires java.sql;          // a named module, part of Java
>     requires jackson.core;      // an unnamed module, name extract from
> filename (jackson-core-2.6.2.jar)
>     requires jackson.databind;  // an unnamed module, name extract from
> filename (jackson-databind-2.6.2.jar)
> }
>
> or
>
> module { // remove the name, so can never refer to it
>     requires mylib;             // a named module, assume part of Maven
> multimodule project
>     requires java.base;         // a named module, part of Java
>     requires java.sql;          // a named module, part of Java
>     requires jackson.core;      // an unnamed module, name extract from
> filename (jackson-core-2.6.2.jar)
>     requires jackson.databind;  // an unnamed module, name extract from
> filename (jackson-databind-2.6.2.jar)
> }
>
> An example of the dependency jar
>
> module org.joda.convert {
> //  requires ??guava??; no named module yet, will be picked up from
> classpath
> }
>
> other projects could already refer to org.joda.convert if they want to.
> Once guava is a named module, org.joda.convert can specify it.
>
> regards,
> Robert

-- 
- DML


More information about the jpms-spec-experts mailing list