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