Accessibility of nonexported types
David M. Lloyd
david.lloyd at redhat.com
Tue Dec 27 09:48:41 PST 2011
On 12/27/2011 09:22 AM, Jesse Glick wrote:
> On 12/23/2011 06:54 PM, David M. Lloyd wrote:
>>>>> access to non-exported types is specifically disallowed at run time
>>>>> by the JVM.
>>>>
>>>> Do you mean that you cannot pass a reference of a
>>>> non-exported class instance from a module to another module?
>>>
>>> No, I mean that if you somehow do get a reference to such an object
>>> you won't be able to do anything with it. The JVM's access-checking
>>> machinery won't let you
>>
>> There needs to be a release valve for this equivalent to setAccessible()
>
> To make a potentially confusing subject more concrete, let us say you have
>
> module m1 {exports m1;}
> package m1;
> public abstract class SomeAPI {
> public abstract void run();
> public static SomeAPI instance() {
> return new m1.internal.SomeImpl();
> }
> }
> package m1.internal; // not exported!
> public class SomeImpl extends SomeAPI {
> @Override public void run() {...}
> public void other() {...}
> }
> module m2 {requires m1;}
> package m2;
> public class APIClient {
> void use() {
> m1.SomeAPI obj = m1.SomeAPI.instance();
> // ...now see below
> }
> }
>
> Obviously APIClient.use can call "obj.run()". Almost as obviously, it
> cannot refer statically to m1.internal.SomeImpl: using modular javac
> that would not even compile; and if you used nonmodular javac or an
> assembler to force it to do so, the module system would throw some sort
> of linkage error when loading or running APIClient. (A module system
> based on a current JRE would throw NoClassDefFoundError, wrapping a
> ClassNotFoundException intentionally thrown from a ClassLoader.loadClass
> override on m2's loader.)
>
> The subtlety is whether APIClient can use reflection to bypass the
> intent of package exports. In the analogous situation in the NetBeans
> module system, and I guess in OSGi as well, the following will run:
>
> obj.getClass().getMethod("other").invoke(obj);
>
> since this bypasses the trigger - attempting to load
> "m1.internal.SomeImpl" from m2's ClassLoader.
>
> Under Jigsaw I would expect the call to Method.invoke to throw
> IllegalAccessException, unless you rewrite to
>
> Method m = obj.getClass().getMethod("other");
> m.setAccessible(true);
> m.invoke(obj);
>
> and the SecurityManager does not complain.
I disagree. I don't see a practical application for this kind of
accessibility constraint. It is redundant with respect to accessibility
modifiers on the class. If we have a module-level accessibility
modifier, then providing an additional check for non-exported public
classes is redundant at best. At worst it makes it impossible for users
to provide a public class under a non-exported package (think again of
frameworks, JavaBeans spec etc.).
I say let visibility be controlled by exports, and let accessibility be
controlled by modifiers, and we sidestep this whole business. It's
cleaner, and frankly less surprising in my opinion.
--
- DML
More information about the jigsaw-dev
mailing list