Yes, a ClassCastException could only arise when (sticking with Paul's scenario) the same class exists in both the named module and the unnamed module.

It would be "safe" for the module system to allow a package that is split perfectly between modules: no overlap of classes and no cyclic references between members. This is checkable when a package is split between two named modules that the resolver can observe in great detail. (You don't even need to check no-cyclic-references, since it's dominated by the no-cyclic-dependencies rule for the modules -- basically the split has to be perfect for the package to work at all.)

But in the case of a package split between a named module and the unnamed module, the check is basically impossible, since the resolver can't enumerate the A.* types in the unnamed module without scanning the classpath, which sounds bad.

tl;dr We don't want a lot of gymnastics in the module system to support a known-bad idiom which most Java developers will never come across. ("most" means "in the millions".)

Alex

On 3/9/2016 5:16 PM, Russell Gold wrote:
Doesn’t this kind of error only happen when a second module exports
the same _class_? What is the problem with another class being
defined in the same package, given that package B isn’t going to
access that new class at all?

- Russ

On Mar 9, 2016, at 4:37 PM, Alex Buckley <alex.buck...@oracle.com>
wrote:

Presumably you would count the equivalent scenario on JDK 8 -- my
package A is in Alex.jar on the classpath and your package A is in
Paul.jar on the classpath -- as a security issue too, because some
of my classes may substitute for yours (or some of yours for mine,
depending on how the classpath is constructed).

On JDK 9, we do the "substitution" cleanly. Package A is not split.
That avoids one category of error (ClassCastException). What about
poor package B that finds itself accessing a different package A
than it was compiled with? Well, since package A is exported by a
named module, it's reasonable to assume that the named module
"owns" package A [*], and that the developer of package B
co-bundled some version of package A without renaming it. Dangerous
in JDK 8, dangerous in JDK 9. (We're trying to encapsulate the
internals of a module, which is different from trying to isolate
modules from each other.)

[*] Advanced scenario: the named module exporting A is actually an
automatic module which happened to co-bundle package A. By placing
this JAR on the modulepath to form an automatic module, it
dominates the JAR left on the classpath which also co-bundled
package A.

Alex

On 3/9/2016 1:17 PM, Paul Benedict wrote:
But isn't what your proposing a security issue? Let's say my
package A is in the unnamed module and your package A is in a
named module. You basically took over my code; your classes will
be substituted for mine.

Cheers, Paul

On Wed, Mar 9, 2016 at 2:38 PM, Alex Buckley
<alex.buck...@oracle.com <mailto:alex.buck...@oracle.com>>
wrote:

On 3/9/2016 10:36 AM, Paul Benedict wrote:

From the doc: "If a package is defined in both a named module and
the unnamed module then the package in the unnamed module is
ignored. This preserves reliable configuration even in the face
of the chaos of the class path, ensuring that every module still
reads at most one module defining a given package. If, in our
example above, a JAR file on the class path contains a class file
named com/foo/bar/alpha/AlphaFactory.class then that file will
never be loaded, since the com.foo.bar.alpha package is exported
by the com.foo.bar module."

I would like some clarification. Correct me if wrong, but I think
this entire paragraph is really meant to be about the perspective
from a modularized JAR? If a module has package A, and the
unnamed module has package A, then of course the module's package
A should win.

However, if it is meant to be absolute language, then I
disagree.

The unnamed module should be coherent among itself. If the
unnamed module has package B and relies on classes from package
A, it should still be able to see its own package A. I don't
think modules should be able to impact how the unnamed module
sees itself. That's a surprising situation.


The unnamed module is not a root module during resolution. If
your main class is in the unnamed module (i.e. you did java -jar
MyApp.jar rather than java -m MyApp), then the module graph is
created by resolving various root modules (what are they?
separate discussion) and only then is the unnamed module hooked
up to read every module in the graph.

Hope we're OK so far.

If some named module in the graph exports package A (more than
one module exporting A? separate discussion), then since the
unnamed module reads that named module, the unnamed module will
access A.* types from that named module.

It's hard to imagine the unnamed module NOT accessing A.* types
from that named module. Primarily, we need to avoid a split
package situation where code in the unnamed module sometimes
accesses A.* types from the named module and sometimes from the
unnamed module.

You might say, OK, let code in the unnamed module exclusively
access A.* in the unnamed module rather than exclusively access
A.* in the named module. Then you have two problems:

1. There are issues for named modules in the same class loader
as the unnamed module -- such named modules MUST get A.* from the
named module rather than the unnamed module, and the class
loading mechanism is incapable of switching based on accessor.
It'll be common for named modules to exist in the same class
loader as the unnamed module, as modular JARs on the modulepath
and non-modular JARs on the classpath all end up in the
application class loader (modular JARs as named modules;
non-modular JARs jointly as the unnamed module).

2. While the module system is sure that package A exists in the
named module, how would the module system possibly know that
package A exists in the unnamed module? Scanning every class file
in every non-modular JAR on the classpath at startup sounds bad.

Alex



Reply via email to