Feedback on proposal for #ReflectiveAccessToNonExportedTypes

Jason Greene jason.greene at redhat.com
Fri Jul 8 19:38:35 UTC 2016


> On Jul 7, 2016, at 5:10 PM, Alex Buckley <alex.buckley at oracle.com> wrote:
> 
> Hi Jason,

Hi Alex, 

Thank you for the thoughtful reply, I have included some debate below.

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

I don’t view these as distinct concepts, but rather see them as interrelated and complimentary. Encapsulation is critical to inversion of control, because to achieve the decoupling that is required, you need well defined contracts throughout the system. Additionally, the decoupling and flexibility introduced naturally leads to the need to isolate the implementation and internal dependencies of what defines a module. So you certainly need name based filtering as well, the key difference is that you delegate the arrangement of components and modules, as well as specific behavior patterns to other parties that cooperatively define the end system. 

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

I argue that dynamic programming (reflection + setAccessible) was just as much a part of the language as static linking was, and it is one of the most powerful aspects of the language. Strict type safety and linkage has lead to less errors, and dynamic behavior has made it easy to build flexible systems and exceed the limitations of the language itself. You really have the best of both worlds in Java, and that is one of the main reasons I attribute to its success. 

I think it’s also important to note that dynamic systems which utilize inversion of control don’t suffer from the primary negatives of breaking encapsulation, since they aren’t statically defined against an implementation, but are rather generated/derived from it (e.g. don’t suffer from unexpected changes). There is of course always the associated security concerns with such power, but they aren’t unsolvable and most certainly worth the benefits (e.g. the whole ecosystem around Java that we have today).


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

Right thats what I say below. The reason I specifically noted this was to point out that the drawbacks of exporting everything can’t be solved with qualification (under these particular use scenarios).

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

I have a hard time seeing this as anything other than boilerplate, and I feel users will feel the same way about it. More specifically, in container/ioc frameworks today, sticking an annotation on a class is all that is necessary to signal your intention, and there is really nothing special about modularity that alters that expectation. 

There is also a disparity here that the JDK itself doesn’t require you to export packages (e.g. I don’t need it for Java serialization). Now I realize that there is an effort underway to de-privilege modules, but I suspect that a portion of the JDK will continue to enjoy special power for precisely the same usability concerns that apply to frameworks / standards which extend the platform.


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

Unless I am missing something (not a stretch!) the proposal describes the runtime behavior of a dynamic export being precisely the same as a standard export at runtime, and if that’s the case the compiler isn’t really adding any protection, it’s just more of a tooling nicety. The ability for anyone anywhere in the system to access the method by almost any means is the same (e.g. generate bytecode, compile against a mock class without the dynamic keyword, use reflection etc) as just having a java security manager. 

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

OK I will try to use jigsaw terminology from now on (Apologies in advance for misuse)

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

To me what is the most “Java-like” is what most closely matches how Java operates today (Java 8) and historically since it’s inception. Up until this point security verification has been a context/use based mechanism that can override fixed declarative defaults. I can certainly appreciate wanting some sort of “Java-how-it-ought-to-be”, and I don’t think solving these common use-cases really precludes that.

Thanks again,

--
Jason T. Greene
WildFly Lead / JBoss EAP Platform Architect
JBoss, a division of Red Hat



More information about the jigsaw-dev mailing list