This would entail the module system enumerating every JAR on the classpath after creating the module graph, in order to detect whether the unnamed module splits any package exported by any named module. There's no reason to special case JDK modules -- augmenting a user module would lead to errors just as confusing.

(Suppose the system image contains just the java.base and spring.boot modules -- I'm sure the latter's owners are just as concerned about third-party augmentation as we are about the former. In fact, they should be more concerned, since their module is in the application loader so its package-private content would be accessible by a classpath JAR also in the application loader. In contrast, the java.base module is safely in the ivory tower of the bootstrap loader, hence a different run-time package from anything in the application loader.)

There's an obvious bikeshed around this validation behavior -- enabled by default? can I choose the modules to be coated with anti-split paint? can I tweak which parts of the classpath get scanned? can I have a manifest attribute to opt out of being scanned? -- so I suggest you simply record the proposal on jpms-spec-comments.

Alex

On 3/10/2016 1:40 PM, Paul Benedict wrote:
My apologies for omitting some key qualifiers in my explanation. Read
everything as a proposal to prohibit classpath jars from silently
splitting whatever packages the JDK exports. -- Thanks

On Thu, Mar 10, 2016 at 3:25 PM, Paul Benedict <pbened...@apache.org
<mailto:pbened...@apache.org>> wrote:

    Alex,

    For the sake of usability, however, it would be nice if the JDK
    verified that jars do not contain any exported JDK packages. This
    would be an RFE. I understand that in order to avoid split packages
    between modules and classpath, the module version takes precedent.
    For developer vs. developer code, I find that reasoning fine.
    However, I really would like to treat the JDK as "special" (your
    words) because in my experience, I see developers constantly
    perplexed by NoClassDefFoundError when something occurred like you
    just detailed.

    I'd like to refer you to the Servlet 3.1 spec [1], section 10.7.2,
    as an analogous concern to mine. This is the so-called "prohibited
    classes" violation clause:

    "As described in the Java EE license agreement, servlet containers
    that are not part of a Java EE product should not allow the
    application to override Java SE platform classes, such as those in
    the java.* and javax.* namespaces, that Java SE does not allow to be
    modified. The container should not allow applications to override or
    access the container’s implementation classes."

    I don't think it's good usability to let JDK packages in the
    classpath go silently unchallenged and unloaded. I recommend they
    are reported as an error.


    [1] https://java.net/downloads/servlet-spec/Final/servlet-3_1-final.pdf

    Cheers,
    Paul

    On Thu, Mar 10, 2016 at 2:30 PM, Alex Buckley
    <alex.buck...@oracle.com <mailto:alex.buck...@oracle.com>> wrote:

        I see xml-apis.jar (2.0.2) contains:

        - a javax.xml.parser package, which includes a FactoryFinder
        class that's not in Java SE, and

        - a javax.xml.transform package hierarchy, whose types at first
        glance look identical to those in Java SE except for yet another
        FactoryFinder class in javax.xml.transform.

        If you put xml-apis.jar on the classpath, its javax.xml.**
        packages will be ignored. The unnamed module reads the java.xml
        module which exports javax.xml.** packages (assuming java.xml in
        the system image, of course), so the application class loader
        delegates for javax.xml.** packages to the loader responsible
        for the java.xml module. User code that tries to access
        FactoryFinder will get a NoClassDefFoundError.

        There's nothing special about JDK modules here. The same
        NoClassDefFoundError would occur if the system image contained a
        module exporting some package, and a JAR on the classpath
        contained the same package with extra classes, and some code on
        the classpath tried to access those extra classes. Since the
        module in the system image is probably the rightful
        owner/exporter of the package, hard questions should be asked
        about the provenance of the JAR on the classpath.

        There has been some discussion of a jdeps-like tool that detects
        when a JAR on your classpath is trying to split a JDK package:
        
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-November/005227.html.

        Alex

        On 3/10/2016 10:27 AM, Paul Benedict wrote:

            Alex, there are JARs that contain javax packages. Anyone in
            the web
            development community knows how many people have included
            xml-apis in
            their WEB-INF :-) only to find out it wasn't loaded or it
            took precedent
            over the JDK versions.

            Has Jigsaw introduced any restrictions here on this front?
            Honestly, I
            think the JDK should make it illegal for the classpath to
            contain ANY
            packages that the jdk has. Please opine when it is
            convenient for you.

            Cheers,
            Paul

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

                 Paul, thank you for asking. The module system's
            treatment of the
                 unnamed module vis-a-vis named modules is probably the
            biggest
                 factor affecting usability of the module system. This
            is true almost
                 by definition because at JDK 9 GA the only named
            modules in the
                 world will be the JDK's while every other class will be
            in the
                 unnamed module of the application class loader.

                 So please, ask more questions about the unnamed module.
            I am
                 especially interested to know if anyone has JARs that
            contain javax
                 packages (or heaven forbid, sun or com.sun packages)
            found in the
                 JDK -- such JARs are a mortal danger to interop between
            unnamed and
                 named modules.

                 Alex

                 On 3/9/2016 1:47 PM, Paul Benedict wrote:

                     Thank you Alex. Since it's roughly the same as JDK
            8, then it's
                     also not
                     worse. I defer to your explanation on that point.

                     Cheers,
                     Paul

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

                     <mailto:alex.buck...@oracle.com
            <mailto: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>
                     <mailto:alex.buck...@oracle.com
            <mailto:alex.buck...@oracle.com>>
            <mailto:alex.buck...@oracle.com <mailto:alex.buck...@oracle.com>
                     <mailto:alex.buck...@oracle.com
            <mailto:alex.buck...@oracle.com>>>
                              <mailto:alex.buck...@oracle.com
            <mailto:alex.buck...@oracle.com>
                     <mailto:alex.buck...@oracle.com
            <mailto:alex.buck...@oracle.com>>

                              <mailto:alex.buck...@oracle.com
            <mailto:alex.buck...@oracle.com>

                     <mailto: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