MethodHandles.Lookup and modules

Alan Bateman Alan.Bateman at
Mon Dec 14 15:02:12 UTC 2015

On 11/12/2015 20:38, John Rose wrote:
> :
>>> 2. downward monotonic
>>> 2a. never has more privileges than L (for all L, A)
>>> 2b. never has more privileges than a full power lookup on A 
>>> (for all L, A)
>>> 2c. as a corollary, a chain… has no more 
>>> privileges than L or any lookups in A, B, C, …
>> Preserved with the exception of A, B and C in the same named module M 
>> and where the set modules that M reads increases (say where code in M 
>> reads additional modules).
> Does this mean adding edges to the readability graph at M?
> If so, then that's covered by the blanket exception mentioned later.
> If you mean something else, maybe we need a point 2d.
Yes, it's adding a directed edge so that M reads other modules. Only 
code in M can do this.

In graph terms then the vertices in the readability graph are the 
modules. A directed edge from module M to module M2 means that M reads 
M2. The graph is mutable in that edges can be added via the API at 
runtime. Code in module M can add a directed edge so that M reads M2. 
Code in M2 might add a read edge in the other direction. Code in a 
module cannot change other modules: M cannot change M2 so that M2 reads 
M or M3 or any other module. For completeness then I should say that 
edges are only removed when the the vertices (modules) they connect are 

> :
> That's fine.  There are two main use cases for,
> neither of which require the tracking of long chains of…).
> 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 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 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!)

Case A is where our current approach might be too limited. This may be 
tied into the discussion point as to how to choose A. If A is in the 
same module as LC then it's as before. However if code in named module M 
creates a full-power lookup and chooses A in another module M2 then the 
resulting has zero access.

It wouldn't be hard to change this to allow PUBLIC be preserved so that would at least allow access to public types in packages that are 
exported unconditionally by the modules that m(A) reads. Would that 
increase usefulness? Would such cases be cases where PL is equally useful?

Preserving PUBLIC would mean compromising on the guarantee that there be 
no more access that the original but that is only because m(A) might 
read modules that m(LC) does not read. It would not give access to 
non-exported types in m(A). It would also not give access to public type 
in packages that are conditionally exported to m(A).

> :
> Going back to graceful degradation:
> 3e. If A is in a named module and LC in the unnamed module (or L is a 
> public lookup), only public names readable from A are retained
> And then we get:
> 4. downward convergence to empty privileges
> 4a. if A is inaccessible to LC=L.lookupClass, has no privileges
> 4b. if A and LC are in different named modules, has no 
> privileges (there is no attempt to retain an intersection of 
> readability sets)

Yes to both.

>> No downward convergence to publicLookup because 
>> m(publicLookup.lookupClass) must read all modules, thus a superset of 
>> the modules that named modules will read. I should say of course that 
>> the publicLookup can only be used to create method handles to public 
>> members in packages that are exported unconditionally.  So nothing 
>> that code in a named module couldn't otherwise access when it 
>> increases readability.
> Right.  (FWIW, the term "unconditional" is not in the Lookup javadoc.)
I looked over the javadoc after Stanislav's first mail and it does need 
to be expanded and improved. In particular, It does not make clear that 
it does not allow access to types in packages that are exported 
conditionally (or "qualified exports" as we have been calling them).

> 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.
> I guess that is the effect of and point 3a, right?
Yes, gives us this.

More specifically, if C1 is a public and in a package exported by M1 
then will result in a Lookup that is C1/public. This lookup 
can only be used to access public types in packages that are exported 
unconditionally and only by modules that M1 reads (assume M1 reads itself).

Alternatively, if C2 is a type in M2 that is not in an exported package 
then will result in a Lookup that is C2/noaccess. This is of 
course because PL.lookupClass() has no access to C2.

> :
> OK, then:
> 5. publicLookup has a reasonable minimal set of globally acceptable 
> privileges
> 5a. this set of privileges is singular, and does not depend on the 
> lookupClass (but it will always be in the unnamed module)
> 5b. the only possible results of are no change, and 
> (following 3e) a public-only access from a named module
Yes to all of these.

>> We have looked of taking snapshots and persisting intersections but 
>> it diverges from bytecode behavior which I think rules it out.
> Well, other lookups diverge from bytecode behavior also, but only by
> dropping away access modes (like private, package, etc.).
> This covers use case A above.  You could argue that intersecting
> readability sets is useful in a similar way, but it is way too complex.
> We don't aspire to create a Lookup object on exactly three API
> points and no more—that's overkill.  A hypothetical application
> that wants to express intersections (or unions) of Lookup capabilities
> can build this on top of lookups.
Yes, the intersection would be complex, more so when qualified exports 
are taken into account. Preserving PUBLIC might be a compromise, 
assuming it is useful.


More information about the jigsaw-dev mailing list