Hi Jason,
On 7/7/2016 1:17 PM, Jason Greene wrote:
I wanted to second Paul’s comments on jams-spec-comments[1], but with
some additional thoughts.
The proposal takes a step in the right direction by allowing a
runtime path to bypass access control. However, the fundamental issue
at play is that class visibility is being used as an access control
mechanism, and these concerns are really orthogonal notions. One of
Java’s most powerful historic capabilities is that it is fully
introspective and dynamic, and this has empowered a large ecosystem
of frameworks and platforms that have extended the language in novel
ways. All of which ultimately lead to it being a dominant server side
development platform.
A major commonality in modern programming models is the notion of
inversion of control. For those unaware, with IOC, a fundamental
notion is that the user defines code which is solely focused on a
particular concern, and it is completely unaware of other parts of
the system which later enhance that code. JSR 250 (part of SE),
demonstrates an example, the user simply needs to add a few
annotations, and their classes are dynamically augmented at runtime
with new behavior. JSR 330 (also part of SE) is another, a container
of some sort is responsible for constructing classes that could be
anywhere in any module and injecting those instances based on some
set of rules into other classes’ private fields. This sort of thing
is very pervasive (most specs that make up Java EE, JPA, Spring,
JAXB, CXF, custom serialization frameworks, mock frameworks, etc).
Even the JDK itself needs this ability.
I call this the "School of Abstraction" form of modularity, which is
about hiding _values_, versus the "School of Encapsulation" form of
modularity, which is about hiding _names_.
The Java language and VM, with their name-based rules for accessibility,
have long been in the Encapsulation school. IoC technologies, with their
abstraction over class instances, are in the Abstraction school. They
had to look outside the Java language and VM, to Core Reflection
(java.lang.reflect), to circumvent name-based accessibility (setAccessible).
In SE 9, the Java language and VM gain stronger name-based accessibility
(unexported package ==> inaccessible public types) without a
corresponding uplift in Core Reflection to let IoC technologies
circumvent it. Thus, tension between the two schools.
This brings us to the problem with the proposal. The expectation
AFAICT appears to be that the user defining the enhanced code knows
the identity of the module enhancing it (e.g. exports dynamic
com.foo.app.model to jpa). The module is simply not in a position to
know that just “jpa” requires access. There might be more than one
version of jpa which needs to be selected dynamically, or jpa might
be broken into multiple modules itself. It’s effectively bleeding
container/framework implementation details into the user defined
code.
'exports dynamic' does not have to be qualified with a 'to' clause.
To run reliably in a Java EE container, the user would have to not
qualify dynamic export, and also define an export on everything to
every module always. But then we run into a lot of boiler plate that
has to always be added by the user and is easily forgotten and/or
misconfigured for a very common use case. This runs counter to the
goals of many modern programming models, which seek to eliminate
boilerplate.
A long 'exports dynamic' list is precisely the tension between the two
schools. Even if an IDE generates and maintains it, its presence is a
reminder to the developer that his module's _internal packages_ are
inspected at run time by _external forces_. I understand the viewpoint
that says "So what? It's the Java way for frameworks to peek into user
code!", and at the same time I appreciate the viewpoint that says
"Explicit definitions of a module's content and surface are a good thing
for long-term maintenance".
Additionally now the user is forced to define their visibility wider
than necessary, causing potential conflicts that would have otherwise
been avoided. Also any security benefit the access control check has
seems easily defeated at this point, since IIUC anyone can just
compile against a different definition removing the dynamic
modifier.
Point of order: you mention visibility but visibility is about class
loading, and Jigsaw does not change that. We're talking about
accessibility -- JLS 6.6 and JVMS 5.4.4.
Accessibility at compile time can't be easily defeated since changing
someone else's module declaration to remove 'dynamic' is akin to
changing someone else's type declaration to turn package->public --
simply not done.
One could address the boilerplate/usabilty issue by inverting this
mechanism from opt-in to opt-out (all packages are dynamic export
unless a restriction is specified). However the other visibility
issues aren’t really addressed.
I think the only way to truly solve this problem is to decouple
access control and visibility.
(I know what you mean, but terminology matters, so please excuse the
following paragraph.)
Point of order: accessibility is decoupled from visibility in Jigsaw. I
explain this in exhaustive detail in "Project Jigsaw: Under The Hood" --
see http://openjdk.java.net/projects/jigsaw/talks/.
If the code doing the enhancing/introspection had to obtain the
permission which applied everywhere, this would achieve the necessary
decoupling and still have decent security. In fact this is already
accomplished with the Java security manager today. However if a
duplicate mechanism is truly necessary, perhaps a special signed code
mechanism, similar to what JSSE providers do today is workable,
albeit a bit burdensome to framework developers
This boils down to a use-site mechanism for saying "I get access!", in
contrast to a declaration-site mechanism like 'exports dynamic' which
says "He gets access!". We tend to think declaration-site mechanisms are
more Java-like, e.g. accessibility modifiers, e.g. default methods.
One proposal that was brought up long ago to improve access control
that I thought seemed quite powerful would have been to support
granting access of package-protected to other modules. That would
have resulted in far less things being made public, which I suspect
is the motivation for adding additional access control checking. I
imagine it’s too late for something like that, but worth mentioning.
There are many ways to tweak the meaning of accessibility modifiers
(including the zero-length package access modifier) but fundamentally
this proposal was a declaration-site mechanism like 'exports [dynamic]'.
Alex
Thanks, Jason
[1]
http://mail.openjdk.java.net/pipermail/jpms-spec-comments/2016-June/000053.html
-- Jason T. Greene WildFly Lead / JBoss EAP Platform Architect
JBoss, a division of Red Hat