Spring's need for optional dependencies

2015-12-17 Thread Juergen Hoeller
Hi everybody,

Juergen from the Spring team here. Quick intro: Spring Framework project
lead since 2003, currently focusing on the Spring Framework 4.3 / 5.0
strategy for 2016-2017.

After extensive conversations with Mark and Alan at Devoxx Belgium in
November, I'd like to summarize our need for optional dependencies from
Spring's perspective:

Our module arrangement in the Spring Framework project has been pretty
stable for about 10 years, splitting the core framework into ~20 modules
with a maximum size of ~1 MB each (some are much smaller). The module split
is largely based on domain (e.g. aop, beans, jdbc, messaging, orm, web,
webmvc, websocket), with each of those modules bringing in a few required
dependencies but in particular also optional dependencies which only apply
when certain third-party frameworks are used in combination with Spring.
Such external frameworks are up for the user to choose; Spring just reacts
to their presence and auto-configures itself for integration with those
frameworks. For example, when Jackson is present, we automatically register
message converters for it; when Joda-Time is present, we automatically
register type converters for its value types. This auto-configuration
experience is long-established in the Spring world, not only for
third-party libraries but also for the JDK: currently between 6, 7 and 8,
for example registering java.time converters automatically when JDK 8 is
present (along the lines of our Joda-Time support).

We have had tight OSGi alignment a few years back, with the framework
modules shipping bundle manifests out of the box. We backed out of this
again since it turned out to be a pain to maintain on our side, in
particular due to the inclusion of version ranges but also due to the
extensive length of the resulting manifests in our jar files. There are
still variants of the Spring modules which include OSGi metadata but they
are maintained by the Virgo project at Eclipse. The canonical Spring
Framework jars from Maven Central come without any such metadata at present.

Now, as of Spring Framework 5, we aim for being the best possible citizens
in a Jigsaw world (while retaining compatibility with JDK 8 at the same
time). Our roadmap is closely aligned with JDK 9 there, and we've got a
first milestone scheduled for June 2016 now. However, there is a
showstopper with Jigsaw: We cannot express the above-mentioned optional
dependencies at this point. Note that Spring's auto-configuration
experience just implies optionality at runtime; those dependencies are in
fact required at compile-time. We'd just like to let our framework modules
bootstrap even when none of those optional dependencies are present,
dealing with the resulting ClassNotFoundExceptions ourselves (we're simply
checking for the presence of certain classes and derive auto-configuration
decisions on that basis). This has been working pretty well for us for 10+
years, and we really need this to keep working when declaring our framework
modules with Jigsaw-compliant module-info files. After all, we'd love to
ship explicit metadata, not keep relying on classpath-like deployment where
such implicit access to other modules remains available.

The alternative would be decomposing the framework into finer-grained
modules which isolate each such dependency into its own module. Aside from
bumping up the number of core framework modules from ~20 to >50 that way,
we'd also lose most of our auto-configuration experience. Making the user
declare such integration modules explicitly is exactly what we're trying to
avoid: Instead, declaring a specific Spring module and a specific
third-party module should be all that it takes, e.g. spring-webmvc and
jackson-databind but no extra spring-webmvc-jackson.

So in summary, we have a strong need for some kind of optional marker in
Jigsaw dependency declarations, similar to optional resolution in OSGi.
Runtime optionality is all that it takes for our purposes: no different
treatment at compile time needed, just lenient bootstrapping which lets us
run into ClassNotFoundExceptions and deal with those. I imagine other
frameworks will be in a similar situation.

It'd be my pleasure to discuss our requirements in more detail if needed...

Juergen


hg: jigsaw/jake/jdk: Reverting mistakenly submitted patch for sjavac

2015-12-17 Thread erik . joelsson
Changeset: b20c9733ab0b
Author:erikj
Date:  2015-12-17 11:02 +0100
URL:   http://hg.openjdk.java.net/jigsaw/jake/jdk/rev/b20c9733ab0b

Reverting mistakenly submitted patch for sjavac

! make/gendata/GendataBreakIterator.gmk



hg: jigsaw/jake: Reverting mistakenly submitted patch for sjavac

2015-12-17 Thread erik . joelsson
Changeset: 89666c1768e8
Author:erikj
Date:  2015-12-17 11:02 +0100
URL:   http://hg.openjdk.java.net/jigsaw/jake/rev/89666c1768e8

Reverting mistakenly submitted patch for sjavac

! make/common/JavaCompilation.gmk
! test/make/TestJavaCompilation.gmk



Wrap-up on Ceylon and Java 9

2015-12-17 Thread Stephane Epardaud
Hi,

I've summed up the work I did on making Ceylon modules compile and run
on Java 9 here: http://ceylon-lang.org/blog/2015/12/17/java9-jigsaw/

Feel free to give it a try :)

Cheers and thanks for the help!



Re: Spring's need for optional dependencies

2015-12-17 Thread Peter Levart

Hi,

On 12/17/2015 12:03 PM, Stephen Colebourne wrote:

And here are the threads for Joda projects, which also need optional
dependencies:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005462.html
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005638.html

Note, I do not consider command line flags to be acceptable as a solution.

Stephen


On 17 December 2015 at 09:41, Stephane Epardaud  wrote:

As I already mentioned, we also have the need for this in Ceylon, for
the same reasons. Dependencies are required at compile-time but optional
at run-time, based on detection: if it's there fine, if not then no problem.



The only problem I see with optional dependencies at runtime is as 
follows...


If "requires optional X" semantic was to include the module X in 
configuration if it could be found with module finder (on -modulepath), 
otherwise not, then the established configuration would not only be 
dependent on command-line arguments, but also on the content of module 
directories. If there was a common directory used as a repository for 
various modules, you would not be able to opt-out of using a particular 
module if it was declared as optional dependency and included in the 
modulepath.


So instead of assembling command-line arguments (-addmods ...), you 
would be forced to assemble private module directories for each 
particular configuration.


Contrasting this with what we have now, the classpath: you have to 
declare that you use a particular optional dependency on command line, 
by mentioning it on the -classpath. And when you do that (assemble a 
-classpath command line argument), the configuration does not even check 
that it really is there. If the .jar file isn't there, it is simply ignored.


So I think the safe "requires optional X" semantic would have to be such 
that it acts as two descriptors:


requires X - at compile time

nothing - at runtime (no attempt to find the module and add it to 
configuration)


You would still have to put -addmods X to command line, but then you 
would have a total control over configuration from command-line only.


Optional dependencies basically then just reduce to a means to have two 
different descriptors: one for compile-time and one for run-time, where 
run-time has a sub-set of requires from compile-time descriptor. It can 
be done now (with separate compilation), but it would be convenient to 
have a single descriptor with two scopes of requires.


Regards, Peter



Re: Spring's need for optional dependencies

2015-12-17 Thread Paul Benedict
Peter, thanks for your comments. I differ in that I don't see any problems
with optional dependencies. Right now, like in Spring, optional features
are enabled with a Class.forName() runtime check; if ClassNotFoundException
is captured, the feature is unavailable. I expect that coding pattern to
continue with optional dependencies. Libraries know how to check if a class
is available and fallback to another plan when it's not.

Regarding your concern on the command line, I am not sure if people will be
using the command line often. I expect tools to eventually read the Module
Descriptors and assemble the correct list of modules. I believe Maven is
currently investigating something similar right now. Currently, Jigsaw only
reads a module directory, but eventually individual jars will be able to be
listed. Just let tools solve this problem.

Cheers,
Paul

On Thu, Dec 17, 2015 at 10:58 AM, Peter Levart 
wrote:

> Hi,
>
>
> On 12/17/2015 12:03 PM, Stephen Colebourne wrote:
>
>> And here are the threads for Joda projects, which also need optional
>> dependencies:
>>
>> http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005462.html
>>
>> http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005638.html
>>
>> Note, I do not consider command line flags to be acceptable as a solution.
>>
>> Stephen
>>
>>
>> On 17 December 2015 at 09:41, Stephane Epardaud  wrote:
>>
>>> As I already mentioned, we also have the need for this in Ceylon, for
>>> the same reasons. Dependencies are required at compile-time but optional
>>> at run-time, based on detection: if it's there fine, if not then no
>>> problem.
>>>
>>
>
> The only problem I see with optional dependencies at runtime is as
> follows...
>
> If "requires optional X" semantic was to include the module X in
> configuration if it could be found with module finder (on -modulepath),
> otherwise not, then the established configuration would not only be
> dependent on command-line arguments, but also on the content of module
> directories. If there was a common directory used as a repository for
> various modules, you would not be able to opt-out of using a particular
> module if it was declared as optional dependency and included in the
> modulepath.
>
> So instead of assembling command-line arguments (-addmods ...), you would
> be forced to assemble private module directories for each particular
> configuration.
>
> Contrasting this with what we have now, the classpath: you have to declare
> that you use a particular optional dependency on command line, by
> mentioning it on the -classpath. And when you do that (assemble a
> -classpath command line argument), the configuration does not even check
> that it really is there. If the .jar file isn't there, it is simply ignored.
>
> So I think the safe "requires optional X" semantic would have to be such
> that it acts as two descriptors:
>
> requires X - at compile time
>
> nothing - at runtime (no attempt to find the module and add it to
> configuration)
>
> You would still have to put -addmods X to command line, but then you would
> have a total control over configuration from command-line only.
>
> Optional dependencies basically then just reduce to a means to have two
> different descriptors: one for compile-time and one for run-time, where
> run-time has a sub-set of requires from compile-time descriptor. It can be
> done now (with separate compilation), but it would be convenient to have a
> single descriptor with two scopes of requires.
>
> Regards, Peter
>
>


hg: jigsaw/jake/langtools: Update Layer API to make it easy to create layers without needing to provide

2015-12-17 Thread alan . bateman
Changeset: 1def640be25b
Author:alanb
Date:  2015-12-17 17:00 +
URL:   http://hg.openjdk.java.net/jigsaw/jake/langtools/rev/1def640be25b

Update Layer API to make it easy to create layers without needing to provide
class loaders

! src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
! src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleWrappers.java



hg: jigsaw/jake/jdk: 2 new changesets

2015-12-17 Thread alan . bateman
Changeset: 74b5562461a5
Author:alanb
Date:  2015-12-17 17:00 +
URL:   http://hg.openjdk.java.net/jigsaw/jake/jdk/rev/74b5562461a5

Update Layer API to make it easy to create layers without needing to provide
class loaders

! src/java.base/share/classes/java/lang/ModuleClassLoader.java
! src/java.base/share/classes/java/lang/reflect/Layer.java
! src/java.base/share/classes/java/util/ServiceLoader.java
+ src/java.base/share/classes/jdk/internal/misc/Loader.java
+ src/java.base/share/classes/jdk/internal/misc/LoaderPool.java
! src/jdk.jlink/share/classes/jdk/tools/jlink/TaskHelper.java
+ test/jdk/jigsaw/reflect/Layer/BasicLayerTest.java
+ test/jdk/jigsaw/reflect/Layer/LayerAndLoadersTest.java
- test/jdk/jigsaw/reflect/Layer/LayerTest.java
+ test/jdk/jigsaw/reflect/Layer/src/m1/module-info.java
+ test/jdk/jigsaw/reflect/Layer/src/m1/p/Main.java
+ test/jdk/jigsaw/reflect/Layer/src/m1/p/Service.java
+ test/jdk/jigsaw/reflect/Layer/src/m2/module-info.java
+ test/jdk/jigsaw/reflect/Layer/src/m2/q/Hello.java
+ test/jdk/jigsaw/reflect/Layer/src/m3/impl/ServiceImpl.java
+ test/jdk/jigsaw/reflect/Layer/src/m3/module-info.java
! test/jdk/jigsaw/reflect/Proxy/ProxyClassAccessTest.java
! test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java
! test/jdk/jigsaw/scenarios/container/src/container/container/Main.java
! test/jdk/jigsaw/util/ServiceLoader/ServicesTest.java

Changeset: 2cf87b107845
Author:alanb
Date:  2015-12-17 17:44 +
URL:   http://hg.openjdk.java.net/jigsaw/jake/jdk/rev/2cf87b107845

Add new entry point for rmic tool

! make/launcher/Launcher-jdk.rmic.gmk
+ src/jdk.rmic/share/classes/jdk/rmi/rmic/Main.java



Re: MethodHandles.Lookup and modules

2015-12-17 Thread Alex Buckley

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


hg: jigsaw/jake/jdk: Update definePackage @throws IAE javadoc and builtin loader to handle IAE case

2015-12-17 Thread mandy . chung
Changeset: ec4fb763dbce
Author:mchung
Date:  2015-12-17 12:10 -0800
URL:   http://hg.openjdk.java.net/jigsaw/jake/jdk/rev/ec4fb763dbce

Update definePackage @throws IAE javadoc and builtin loader to handle IAE case

! src/java.base/share/classes/java/lang/ClassLoader.java
! src/java.base/share/classes/jdk/internal/misc/BuiltinClassLoader.java



Result: New Jigsaw Committer: Jan Lahoda

2015-12-17 Thread Jonathan Gibbons


Voting for Jan Lahoda [1] is now closed.

Yes: 6
Veto: 0
Abstain: 0

According to the Bylaws definition of Lazy Consensus, this is
sufficient to approve the nomination.

Jonathan Gibbons

[1] 
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005534.html


Re: MethodHandles.Lookup and modules

2015-12-17 Thread John Rose
On Dec 14, 2015, at 7:02 AM, Alan Bateman  wrote:
> ...
> 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 GC'ed.

This graph of the "M1 READS M2" relation is a handy visualization.
How does it interact with exports, and the unconditional/qualified distinction?
Let me try to figure it out…

I guess the READS edges would be labeled by the types that flow across them.
Let's say TYPES_VIA(M1 READS M2) = {m2pkg.P, m2pkg.Q, …} is the set of
types (all public) from M2 that M1 can read.

And, I guess that TYPES_VIA(M1 READS M2) contains exactly
M2's unconditional (non-qualified) exports, plus M2's qualified
(non-unconditional) exports to M1.

Which is not to say that code in M1 actually uses all those types,
but it could.  And it can't use anything else from M2.

Yes?  (TIA)

>> 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. …
> 
> 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 
> L.in(A) has zero access.
> 
> It wouldn't be hard to change this to allow PUBLIC be preserved so that 
> L.in(A) 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?

Hmm…  What PL does is ignore the M1 READS M2 graph, or (equivalently)
adds temporary edges as needed to access unconditionally exported names.

(Anticipating a reply to Alex's message of today…)  Possibly, a PUBLIC-type
lookup QL would only be able to see types readable by M1=MODULE(QL.LC).
That is, QL (possibly) would respect the READS graph as it exists, and not
attempt to extend it on the fly like PL (publicLookup) does.  Points about this:

1. Such a lookup QL is stronger than PL in that it might see qualified exports
readable by M1.  (This would be Alex's QUALIFIED mode, which I like.)
But QL would also be weaker than PL, in that it would respect the existing
READS edges, and not create temporary edges like PL does.  (Am I right
that this is a real distinction?  I'm coming up to speed here!)

2. The restriction on QL is interesting in theory but maybe not in practice.
After all, if a nosy browser of modules wants to see an unconditional export
from M2, he doesn't need to bother with a QL in M1; he just uses PL.

3. How much do we all care that modules are completely leaky in their
unconditional (unqualified) exports?  It's really helpful that a module
can hide its unexported types (and seal them up for optimization, etc.).
It's also helpful that modules can use qualified exports to be friends.
Do we (can we) discourage Java apps from browsing modules
for their unconditional exports?  I'm guessing "no (and no)" is the answer.
If that's true then there is little reason to limit any QL's ability to be
a superset of PL.

4. OTOH, suppose a user is trying to be a good citizen of Module World,
and wants to avoid accessing unqualified exports in the absence of a
previously declared READS edge.  It that a real use case?  If so, then
having a QL that throws an error if a READS edge is missing will help
debug the READS graph, instead of sweeping errors under the rug.
From this point of view, usage of PL would be slightly bug-prone, since
PL ignores the carefully constructed READS graph.

Bottom line:  If the READS graph provides useful restrictions, even
for unconditional (unqualified) exports, then it would be useful to
have a QL (not stronger than PL) which emulates a lookup from
some M1, including the *inability* to read any old export..

Bottom line #2:  I like Alex's suggestion of having a QL which
mimics the lookup "perspective" of public types visible to some M1,
but external to M1.  (This QL would be not weaker than PL, as well
as not stronger.)  I was kind of fishing for that extra "mode bit",
and I think we caught something.

Bottom line #3:  If we believe that QL should be incommensurable
with PL, it follows that PL has unique 

Re: Spring's need for optional dependencies

2015-12-17 Thread Stephen Colebourne
And here are the threads for Joda projects, which also need optional
dependencies:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005462.html
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005638.html

Note, I do not consider command line flags to be acceptable as a solution.

Stephen


On 17 December 2015 at 09:41, Stephane Epardaud  wrote:
> As I already mentioned, we also have the need for this in Ceylon, for
> the same reasons. Dependencies are required at compile-time but optional
> at run-time, based on detection: if it's there fine, if not then no problem.


Re: MethodHandles.Lookup and modules

2015-12-17 Thread John Rose
On Dec 17, 2015, lookup modest 12:44 PM, Alex Buckley  
wrote:
> 
> … please consider the following design:
> 
> - PUBLIC lookup mode means:
> 
>  Any 'public' type of any package exported unconditionally by the package's 
> module.

Accessing those is the uniquely special power of PL=publicLookup, which 
cavalierly
ignores the READS graph, and therefore does not need  to be computed relative 
to anything.

For clarity I would like to give this thing a special name, UNCONDITIONAL.

UNCONDITIONAL(M1) = { T, if IS_PUBLIC(T), in PACKAGE_TYPES(P), if 
IS_UNCONDITIONALLY_EXPORTED(P), for P in MODULE_PACKAGES(M1) }

UNCONDITIONAL() = UNION { UNCONDITIONAL(M1), for M1 in ALL_MODULES }

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

QUALIFIED(M1) = { T, if IS_PUBLIC(T), for T in PACKAGE_TYPES(P), if 
IS_CONDITIONALLY_EXPORTED(P, M1), for P in MODULE_PACKAGES(M2) }

L_QUALIFIED(L) = QUALIFIED(TYPE_MODULE(L.LC))

N.B. This leaves the following related expression as an orphan (cannot be 
recomposed from the others):

- READABLE(M1) lookup mode means:

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

READABLE(M1) = QUALIFIED(M1) + UNQUALIFIED(M1)
  where UNQUALIFIED(M1) = UNION { UNCONDITIONAL(M2), for M1 READS M2 in 
READS_GRAPH }

Note that UNQUALIFIED(M1) is a subset of UNCONDITIONAL() for all M1.

These classifications are nicely disjoint, so the eventual nesting
behavior arises by disjoint union.

If PUBLIC/UNCONDITIONAL is the wrong ground-level default (my point today),
then READABLE(M1) is more useful than QUALIFIED(M1).

> - MODULE lookup mode means:
> 
>  Any 'public' type of any package in the lookup class's module.

MODULE(M1) = { T, if IS_PUBLIC(T), for T in PACKAGE_TYPES(P), for P in 
MODULE_PACKAGES(M1)  }

MODULE(M1) is disjoint from READABLE(M1) and QUALIFIED(M1), but not from 
PUBLIC/UNCONDITIONAL.

For lookups we can derive things like:

L_UNCONDITIONAL(L) = UNCONDITIONAL()
L_READABLE(L) = READABLE(TYPE_MODULE(L.LC))
L_MODULE(L) = MODULE(TYPE_MODULE(L.LC))

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

This is a useful building block, but needs to be associated with 
UNQUALIFIED(M1) or UNCONDITIONAL().

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

Or, in terms of my previous message, it could omit PUBLIC/UNCONDITIONAL and be 
READABLE + MODULE + PROTECTED + PACKAGE + PRIVATE

This means that PL is not a subset of all other non-trivial lookups.
It also means that the read-graph blindness stays unique to PL.

> - 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 we started with READABLE instead of PUBLIC/UNCONDITIONAL, the resulting 
lookup
L.in(A) would be degenerate (call it NOACCESS mode).  This surprise would be 
the cost
of recognizing and enforcing the uniqueness of PL.  At the present moment, I 
think
this is the best way to go.

PL.in(A) would continue to be UNCONDITIONAL (as long as A is in 
UNCONDITIONAL()).

(There's no union or non-empty intersection of L and PL, if they do 
incommensurate things.)

For PL I think this simple rule suffices:
>  -- If L is PUBLIC, then L.in(A) is also PUBLIC, unless A is inaccessible to 
> L, in which case L.in(A) has no access.

In fact, a PUBLIC/UNCONDITIONAL lookup is always the result of publicLookup()
itself or a derivative of publicLookup() via a chain of L.in(A).

BTW, there are three global rules that interact with these rules:

-- If A is not accessible to L's lookup class, using L's lookup modes, then 
L.in(A) has no access.

-- In all cases, the lookup modes of L.in(A) are a subset of (or equal to) the 
lookup modes of L.

-- In all cases (assuming no concurrent change in schemata) the set of names 
accessible to L.in(A) is a subset of (or equal to) the set of names accessible 
to L.

The third rule is a very broad requirement with all sorts of detailed 
implications.
All the other rules are designed to add up to the this main rule.

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