MethodHandles.Lookup and modules

Alex Buckley alex.buckley at oracle.com
Thu Dec 17 20:44:03 UTC 2015


Hi John,

On 12/11/2015 12:38 PM, John Rose wrote:
> That's fine.  There are two main use cases for Lookup.in,
> neither of which require the tracking of long chains of L.in(A/B/C…).
>
> A. Agent with full-power lookup wants to invoke another agent with the lookup,
> but wants to limit access, because he doesn't fully trust the other agent.
> He does a single L.in(A) to a remote-enough type A, creating a non-full-power lookup.
> (Note:  Picking A is sometimes non-trivial.  This might be an API flaw.)
>
> B. Agent with full-power lookup wants to get access to private nestmate in A.
> He does a single L.in(A) where LC and A are in the same package member.
> This works around differences between access checks at JVM and JLS levels,
> just as the package-private accessor methods from javac do.  (Yuck!)

Focusing on case A, please consider the following design:

- PUBLIC lookup mode means:

   Any 'public' type of any package exported unconditionally by the 
package's module.

- QUALIFIED lookup mode means:

   Any 'public' type of any package exported in qualified fashion by the 
package's module to the lookup class's module.

- MODULE lookup mode means:

   Any 'public' type of any package in the lookup class's module.

(Sidebar: QUALIFIED is split from MODULE primarily to be explicit about 
access rights and secondarily to support more precise slicing of access 
rights in a future MethodHandles.Lookup API. Example: give me a lookup 
object to access the types in this module that offer a contract, i.e. 
are declared 'public' without regard to exported-ness. Example: give me 
a lookup object to access the types outside this module which are 
exported to it by its friends.)

- Start with an arbitrary class in an arbitrary module calling 
MethodHandles.Lookup.lookup() to get a "full power" lookup object L. L's 
lookup modes are PUBLIC + QUALIFIED + MODULE + PROTECTED + PACKAGE + 
PRIVATE.

- The arbitrary class obtains a Class object representing class A, then 
calls L.in(A):

   -- If A is in a different module than L's lookup class, then the 
resulting lookup object has lookup mode PUBLIC.

   -- If A is in the same module as L's lookup class, but a different 
package, then the resulting lookup object has lookup mode PUBLIC + 
QUALIFIED + MODULE + PROTECTED. (#include some stuff about actually 
accessing protected members outside A's package.)

   -- If A is in the same module as L's lookup class, and in the same 
package, but A is a different class than L's lookup class, then the 
resulting lookup object has lookup modes PUBLIC + QUALIFIED + MODULE + 
PROTECTED + PACKAGE.

   -- If A is the same class as L's lookup class, then the resulting 
lookup object has lookup modes PUBLIC + MODULE + PROTECTED + PACKAGE + 
PRIVATE.

- L.in(A) succeeds (returns a lookup object) regardless of whether its 
caller is in a module that reads A's module. Only when find* is called 
on a lookup object is there a check that the caller-of-find*'s module 
reads the module containing the lookup class embodied by the lookup 
object. It's easy for the caller-of-find* to pass the check by calling 
addReads(...) just before calling find*.

(Sidebar: Separately, the module containing the lookup class embodied by 
the lookup object had better have readability to other modules in order 
for find* to look up [ctors, methods, and fields of] classes in those 
other modules.)

> Should there be a way to build a lookup, for two modules M1/M2, which
> reads those names of M2 which M1 can read, except no internals
> of M1?  I wonder if such a thing would be useful?  Probably not.
>
> But it would be useful to have a lookup in a module M1 which can
> read the exports of *every* M2 that M1 can see, except no M1 internals.
> (This includes the unconditionally exported public names of M1.)
> This would be a Lookup with an LC in M1 and flags of PUBLIC only.

The difference between these two paragraphs is hard to discern. The 
first paragraph seems to fix M1 and M2 while the second paragraph fixes 
M1 and varies M2, but there's also a switch from "M1 can read" to "M1 
can see". Modules read modules, classes see classes, types access types. 
Can you restate?

Alex


More information about the jigsaw-dev mailing list