MethodHandles.Lookup and modules
Alan Bateman
Alan.Bateman at oracle.com
Wed Dec 9 22:16:44 UTC 2015
On 09/12/2015 14:54, stanislav lukyanov wrote:
>
> 1) Lookup.in() javadoc says
> "If the lookup for this Lookup is in a named module, and the new
> lookup class is in a different
> module M, then no members, not even public members in M's exported
> packages, will be accessible"
> However, it seems to be possible to have PUBLIC access after
> lookupInA.in(ClassInB.class)
> without breaking "no more access capabilities than the original" rule.
>
> Are such transitions intentionally forbidden?
Yes, this is intention as the lookup class and mode bits would otherwise
not be sufficient when you teleport through a sequence of lookup
classes. It might be clearer if you extend the example to
in(B.class).in(C.class).in(D.class) where B, C and D are in different
named modules and work out the intersection.
>
>
> 2) Lookup.in() javadoc says
> "If the lookup class for this Lookup is not in a named module, and the
> new lookup class is
> in a named module M, then no members in M's non-exported packages will
> be accessible"
>
> Spec says nothing about M's 'requires' and 'exports to M'.
> In current implementation, modules required by M are still accessible
> and packages exported to M (with 'exports to') are not accessible.
>
> It seems right that packages exported to M are not accessible.
> Should it be specified in the javadoc, or is it implied due to
> definitions somewhere else?
It is implied because the javadoc provides the guarantee that the
resulting Lookup has no more access than the original. In this case
there are packages exported by M's friends to M that are not accessible
to code in unnamed modules. However, I think you are right that this
could be make clearer in the javadoc. I'm sure that once the design
settles down that we'll do several passes over the javadoc.
> :
>
> However, this creates some uncertainty.
> Suppose we have A requires B. From user's point resulting lookup of
> publicLookup().in(ClassInA.class)
> may or may not have access to the module B - it depends on module A's
> 'requires' which user doesn't know about.
>
> It may come to the following situation. Code
> publicLookup().in(BlassInA.class).findStatic(ClassInB.class, "m",
> ...).invoke()
> works with version of A that have 'requires B'.
> In the next version, A removes 'requires B' which should not
> have any impact on A's users, but the code above stops working.
Sure, the other thing is that readability graph can mutate at run-time
so that `A` reads additional modules.
>
>
> 3) publicLookup() seems to allow work around the module access control.
> publicLookup() is available for any module and has access to any
> module's exported packages.
> So, if we have modules A and B that do not require each other, we can
> still access B from A:
> // code in A
> publicLookup().in(ClassInB.class)
>
> Is it OK to be able to do such tricks?
The publicLookup can only be used to access types that are are public
and in packages that are exported unconditionally. It can't be used to
break encapsulation, either directly or by teleporting and using a
lookup class in another module.
Also `A` can call addReads to read any other module so this allows it to
access any public type in any package exported by other modules if it
really wants. This means that there is nothing that the publicLookup can
be used to access that `A` can't access anyway.
-Alan
More information about the jigsaw-dev
mailing list