Preemptively rejected issue: Modules, ClassLoaders, and compatibility

David M. Lloyd david.lloyd at redhat.com
Mon Feb 27 13:44:30 UTC 2017


Since the early days of this JSR, in fact since 2012 (if not earlier), 
long before it was officially formed (which wasn't until the end of 
2014), the design decision in Jigsaw of creating a new concept for 
encapsulation has been the subject of friction and something we've been 
fighting with both technically and politically.  We still hold that this 
decision was in error, and that it is becoming more apparent as time 
wears on and more problems arise with the fundamental architecture of 
Jigsaw.

The justification of this design decision was chiefly made around 
compatibility: having the same types and arrangements of class loaders 
was something that was assumed that many applications would count on. 
Splitting the JDK means that some modules that used to have a "null" 
class loader now no longer would.  JDK modules which had elevated 
privileges would lose them, resulting in breakage and other problems.

Over time, more new rules were introduced regarding reflection, service 
loader, and other behaviors.  These rules have broken compatibility in 
many ways which are, by any evidence, far more widespread than those 
which would result from changing the class loader arrangement of the 
core platform or even class path applications.

Since that time, a laudable initiative has been undertaken to 
de-privilege the core platform, module by module, in the interest of 
security.  This change inherently breaks the previously established 
compatibility criteria in a much more direct manner; each of these 
modules has a class loader value that it did not have before.  The 
logical conclusion of this effort is in fact that every module would be 
de-privileged up to, but not including, java.base.  Any program 
depending on null class loader values would be broken; any JDK code 
relying on this as a security check would need to be updated.

I believe that it was also suggested that forward compatibility for Java 
EE containers which rely on a special class loader structure was a 
justification for this as well.  However, other issues we have raised in 
the name of meeting what we view as the bare minimum for our Java EE 
container's compatibility have been closed, which would invalidate this 
justification as far as I can tell.

Several existing issues, resolved and unresolved, arise solely as a 
consequence of this design choice, including #MultipleModuleVersions and 
#ConcealedPackageConflicts, both of which are still open.  Neither of 
these issues would necessarily exist had this choice been made; on the 
contrary, the question would have been about supporting such 
restrictions as a matter of policy, rather than as a consequence of the 
implementation.  I don't think I am overstepping when I suggest that in 
such a hypothetical case, most developers would express that such 
restrictions should not be added, or that they should only apply on an 
opt-in basis, intuitively seeing the necessity of such things.  In 
addition, there would have been no need to have disparate behavior 
between named and unnamed modules, as this division has clearly arisen 
as an implementation artifact, not a first principle of design (who 
would imagine such a thing themselves?).  Each of these things 
represents a cognitive friction between existing and future code.

Millions upon millions of lines of code of Java exist.  In fact it's 
probably not even countable anymore at this point.  By introducing a 
separated abstraction for the module concept when a largely equivalent 
concept already exists in the form of class loading, every single one of 
these things that relies on traditional class loading behavior is 
needlessly compromised in ways that seem hard to predict and harder to 
justify.  A layer of complexity is added wherein there are now yet more 
different ways in which classes and resources can be found and resolved, 
with more rules layered on top, when the old rules were already 
sufficient as they were.  The Java community deserves a simple, clean 
design that grows intuitively from what they are familiar with.

Allowing "old" code and "new" code to coexist is not a good substitute 
when we could have easily had a new system wherein the vast majority of 
"old" code would have been able to function without change, even were it 
using service loading, class loading, and reflection.

Our opposition to this design choice persists, despite the preemptive 
dismissal of our original and subsequent objections to it.  At least one 
issue that was just recently closed, #LayerPrimitives, existed as part 
of a mitigation strategy to cope with this problem.

-- 
- DML


More information about the jpms-spec-experts mailing list