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