Java Platform Module System
alex.buckley at oracle.com
Fri Apr 28 23:25:49 UTC 2017
On 4/27/2017 12:38 PM, Stephan Herrmann wrote:
> On 25.04.2017 19:02, Alex Buckley wrote:
>> JPMS semantics (notably, dependency resolution) are defined by the API
>> specification (not the implementation) of
>> java.lang.module.Configuration and friends. JLS references to JPMS are
>> references to this Java SE API.
> Got it. Since now JLS is no longer self-contained it would tremendously
> help if we could get a list of which parts of the API specification are
> expected to be considered at compile time. I understand that we need to
> apply the naming rules for automatic modules. Is there more that should
> be respected / validated / enforced at compile time?
The JLS was never self-contained as it always referenced a variety of
java.lang and java.io types (and more recently java.lang.annotation and
java.lang.invoke types). I have changed 7.3 to state:
"The host system must use the Java Platform Module System (as if by
execution of the 'resolve' method of java.lang.module.Configuration) to
determine which modules are read by M (§7.7.1). It is a compile-time
error if the Java Platform Module System is unable to determine which
modules are read by M."
That is, if a compiler processes a module declaration mentioning
"requires X;", and the "as if" JPMS resolution fails because no module
called "X" is found (whether an explicitly declared module with that
name, or an implicitly declared i.e. automatic module with that name),
then compilation fails too. The mapping from a JAR filename to an
implicitly declared i.e. automatic module name is part of JPMS
resolution. And even if a module called "X" is found, there are other
reasons why JPMS resolution (and hence compilation) can fail, e.g. the
module requiring X also requires Y and both X and Y export the same
package. The JLS, as is traditional, allows a compiler to be as helpful
or as terse as it likes w.r.t. the content of the compile-time error
> Let me add a friendly reminder, that we are still waiting for a
> specification that unambiguously tells us which module system to implement.
> For illustration:
> (A) Is JPMS a module system that keeps the semantics of qualified names as
> they are in Java 8 and only superimposes encapsulation boundaries?
> (i.e., each type is globally uniquely identified by its qualified name).
> (B) Is JPMS a module system that maintains the assumption that from the
> perspective of each module all relevant types can be distinguished using
> their qualified name?
> (i.e. admitting identical qualified names as long as no compilation of one
> module will ever encounter several candidates at once).
> (C) Is JPMS a module system that establishes a separate namespace for each
> module, where types with identical qualified name - but defined in
> different modules - need to be distinguished?
> (i.e., uniqueness is primarily required for module-prefixed qualified
> Despite some efforts I fail to find a definite answer in JLS (and Alex
> mentioned that some of this is still being discussed). Still JLS as of
> today sounds mostly like (A). To me (B) sounds like the natural choice, but I
> understood Alex as saying it *should* be (C). I don't see, however, how the
> conceptual framework of JLS could possibly support such design.
(B) and (C) are not mutually exclusive because (B) was worded from the
perspective of each module while (C) was not.
(B) is true. Assume two modules M and N each contain the type P.C, but
neither module exports P (or, M exports P and N doesn't, or, N exports P
and M doesn't). Then, a third module O can require M and N. If code in
any module refers statically to a type P.C, then JPMS resolution
guarantees that P.C is either defined by that module or is exported to
the module by exactly one other module which the module reads.
At run time, when 'java' is run with M+N+O on the modulepath, the system
will stop -- M+N+O will pass resolution (i.e. a Configuration will be
constructed) but they can't all be mapped to the application class
loader. javac will produce a lint warning to this effect. However, M and
N and O are by no means "bad" modules, either individually or jointly,
as M+N+O will work if mapped to a multi-loader layer. So, (C) is true too.
The JLS, as is traditional with classes and packages, does not restrict
the modules which can be given as input for an invocation of a compiler.
A compiler is assumed to be able to process multiple modules at once. In
the case of M and N, a compiler will encounter P.C in M and P.C in N,
and is expected to distinguish them -- code in M refers to P.C in M
while code in N refers to P.C in N. This (C)-style property is now
expressed in 4.3.4:
"Two reference types are the same compile-time type if they are declared
in compilation units associated with the same module (§7.3), and they
have the same binary name (§13.1), and their type arguments, if any, are
the same, applying this definition recursively."
> PS: I'm also having hard times to imagine, how those parts of the
> specification, that are focused on compilation units, can possibly define
> aspects like accessibility when looking at .class files, not compilation
> units - but hopefully, this is just a technicality in how the spec is
> worded, not a conceptual problem.
The JLS has never said how a compiler should process a mix of
compilation units and .class files, yet compilers have figured it out.
Everything in 7.3 about the host system associating compilation units
with modules is applicable to associating class files with modules.
More information about the jigsaw-dev