Unnamed module and duplicate package
Alex Buckley
alex.buckley at oracle.com
Thu Mar 10 21:22:25 UTC 2016
Yes, we can keep tightening the split package scenario to ensure safety
without scanning the classpath. First, you have to promise that the JAR
on the classpath never has classes that overlap with a module in the
system image. Second, the named module of interest in the system image
can't be a framework that reflects over classes in the unnamed module
(thus sidestepping bugs about "Where did this class in my package come
from? It's not my codesource! I can't load it starting from my loader!").
To put it mildly, this isn't what we had in mind for "reliable
dependencies".
You also have to consider why the split package occurs at all. Your
classpath JAR might simply be adding public types that you feel a module
in the image should have had all along. Other people will offer up a
classpath JAR that adds public types to access and return
package-private content of a module in the image. This won't work for
most JDK modules, since they're defined by a different loader than the
unnamed module, but it would work for some JDK modules and for all user
modules.
To put it mildly, this isn't what we had in mind for "strong encapsulation".
Alex
On 3/9/2016 7:14 PM, Russell Gold wrote:
> This should, however, be completely safe in the case when one of
> those modules is part of the JDK itself, isn’t it? It is not clear to
> me how you could ever get a circular dependency in that case.
>
> In fact, this should be true of any library as well - the only
> scenario that I can think of where you could get this mess is if a
> developer compiles a bunch of classes, and then deliberately creates
> circularity between modules by putting some of those classes into a
> named module and some into the unnamed module, which seems incredibly
> unlikely.
>
> If there an actual plausible scenario from which you are hoping to
> protect developers with this restriction?
>
> - Russ
>
>> On Mar 9, 2016, at 8:56 PM, Alex Buckley <alex.buckley at oracle.com>
>> wrote:
>>
>> 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.buckley at 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.buckley at oracle.com <mailto:alex.buckley at 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
>>>>>
>>>>>
>>>
>
More information about the jigsaw-dev
mailing list