Java Platform Module System

Alex Buckley 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 
message.

> 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
> names).
>
> 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.

Alex


More information about the jigsaw-dev mailing list