Module declarations

mark.reinhold at oracle.com mark.reinhold at oracle.com
Mon Oct 5 18:47:23 UTC 2015


2015/9/17 10:26 -0700, david.lloyd at redhat.com:
> On 09/17/2015 09:52 AM, mark.reinhold at oracle.com wrote:
>> (splitting your initial reply into separate threads)
>> 
>> 2015/9/9 1:48 -0700, david.lloyd at redhat.com:
>>> ...
>>> 
>>> 1) The first thing that jumps out at me (again) is making module
>>> declarations be a binary construct produced by the actual programming
>>> language.  It strikes me as arbitrary as well as redundant (given
>>> there's a programmatic API to build descriptors, they could simply be
>>> parsed from text nearly as well, and a lot more nicely from the user's
>>> perspective).  As pointed out in the document, it is already expected
>>> that additional tooling would synthesize this file at build time,
>>> further decreasing the value of such an idea.  The module class file
>>> just seems pointless to me.
>> 
>> One of our requirements is fidelity across all phases.  To achieve this,
>> javac (or whatever Java compiler you use) must be able to locate and
>> interpret descriptions of modules.  If modules are not described by
>> language constructs that are compiled into class files, then how and
>> where would you suggest that a compiler find such information?
> 
> They could still be bundled with the artifact, but in clear text format 
> perhaps.  Or even in binary format, but in either case, the descriptor 
> format should be specific to a specific default module configuration 
> (e.g. an application module loader) rather than be a hard-wired aspect 
> of all modules.
> 
> To me "fidelity" means the same thing as "integrity": I can build an 
> artifact and expect it to run on any environment which meets its ABI 
> requirements in any way.  I don't think that hard-coding module 
> dependency names in the artifact itself is a good way to achieve this 
> though.  Doing so hampers the ability to separate building from 
> packaging, since if you need to specify different run time environment 
> parameters in the packaged version, you must crack open and modify the 
> artifact to do so (new SHA1/MD5 checksums, etc.).
> 
> To me a better way to achieve this is a multi-tiered approach, where 
> each tier depends on the tier before (but not vice-versa).
>
> ...

I don't think our views are all that far apart -- we just mean different
things by the term "fidelity".

The fidelity requirement [1] says:

  Resolution, encapsulation, non-interference, services, and all other
  aspects of the module system should, to the fullest extent possible,
  work in exactly the same way at compile time, at run time, and in
  every other phase of development or deployment.

That is, given a particular environment, i.e., a particular module path
and one or more initial modules, etc., the module system will behave the
same way and enforce the same restrictions in every phase.  This is
critical to providing a good developer experience.

Ensuring that the environment actually is the same at multiple points in
time, or "the same enough" within the bounds of acceptable change, is
what I understand you to mean by "integrity".  Integrity is a critical
goal in the configuration and distribution of large systems, but it's
beyond the scope of the module system.

The module system, as proposed, is intentionally limited to the goals
of reliable configuration and strong encapsulation; it is not meant to
address the higher-level problems that are more appropriately the domain
of build tools, packaging systems, container applications, and so forth.
At the language and VM level we need to know a module's name, the names
of the modules it depends upon, and the names of the packages it exports.
Whether the exact same set of modules is provided at compile time vs. run
time is a problem for tools to solve, but if the environments are
identical in each phase then the module system will behave identically.

This is why version selection is an explicit non-requirement [2]; a
version string can be recorded in a module's descriptor, but it's for
informational purposes only.  It's also why we have requirements that the
module system work well with OS-specific packaging systems [3].  We're
trying to fit in to the existing ecosystems for building, packaging, and
distributing Java components, from Maven all the way up to RPM.  We are
not trying to replace them.

There is a small wrinkle in this story, which is perhaps a source of
confusion.  The section of SotMS that describes qualified exports [4]
mentions the idea of recording, in a module's descriptor, the hashes of
the modules that are allowed to depend upon it and use its qualified
exports.  This feature, which is in service of a stated requirement [5],
is meant only for situations, such as with the JDK itself, where a set of
tightly-related modules are developed and built together with a high
level of trust.  It may well prove useful in some non-JDK scenarios but
it is not intended to address the general integrity story, which is more
appropriately addressed by the kind of multi-tier approach you describe.
(I'll add some wording in the next version to make this clear.)

                                  * * *

Now, to get back to the question of the form and placement of module
declarations: To achieve fidelity, i.e., the identical behavior of the
module system at compile time and run time given the same environment,
a Java compiler must be able to locate and interpret descriptions of
modules which contain, at least, the information required (i.e., module
names, dependences, exports).  A JVM must be able to do the same thing,
preferably with the same data.

If these essential properties of modules are not described by language
constructs that are compiled from source files into class files, then
where and in what form would you suggest that a compiler or JVM find
such information?

Bear in mind that a module being compiled is not yet in an artifact, so
whatever form this information takes needs to make sense in, or somehow
alongside of, an "exploded" directory tree of source files.  A module
being compiled against, or even being run, might also be an exploded
directory tree of class files rather than an artifact, so that case
must also be supported.

(See also my reply to Peter on this topic, under the subject line "Why
 not use the Manifest?".)

- Mark


[1] http://openjdk.java.net/projects/jigsaw/spec/reqs/#fidelity-across-all-phases
[2] http://openjdk.java.net/projects/jigsaw/spec/reqs/#version-selection
[3] http://openjdk.java.net/projects/jigsaw/spec/reqs/#packaging
[4] http://openjdk.java.net/projects/jigsaw/spec/sotms/#qualified-exports
[5] http://openjdk.java.net/projects/jigsaw/spec/reqs/#referential-integrity


More information about the jpms-spec-experts mailing list