Implied readability + layers

Alex Buckley alex.buckley at oracle.com
Fri Nov 6 17:50:49 UTC 2015


On 11/6/2015 2:59 AM, Ali Ebrahimi wrote:
> On Fri, Nov 6, 2015 at 4:09 AM, Alex Buckley <alex.buckley at oracle.com
> <mailto:alex.buckley at oracle.com>> wrote:
>
>     com.foo in layer2 requires com.baz in layer1, right? Yes.
>
>     com.baz in layer1 uses types from com.bar in layer1, and NOT from
>     com.bar in layer2, right? Yes.
>
>     Therefore, com.foo uses types from com.bar in layer1 (as required by
>     com.baz in layer1), right? Yes.
>
>     I don't know what it means to say "we use com.bar at 2 for layer2's
>     modules". com.foo is in layer2, and you can make it read com.bar at 2
>     via reflection, but otherwise com.bar at 2 is not read by com.foo
>     because com.baz doesn't know about it.
>
> There is no need for reflection:
> Please follow this sample and test it:
>
> layer 1: com.baz and com.bar at 1
> ---------------------------
>
> module com.bar {//version1
>      exports com.bar;
> }
>
> ------------------
>
> //Bar.java
>
> packagecom.bar;
> public classBar {
>      publicString bar(){return"bar1";}
> }
>
> module com.baz {
>          requires com.bar;
>          exports com.baz;
> }
>
> -----------------
>
> //Baz.java
>
> packagecom.baz;
>
> importcom.bar.Bar;
> public classBaz {
>      publicString baz(){return newBar().bar();}
>      publicBar bar(){
>          return newBar();
>      }
> }

I expect javac will warn about the bar() method of class Baz. As a 
public method in a public type in an exported package, its return type 
is from another module (com.bar), yet module com.baz doesn't set up 
implied readability to that other module. Anyway, moving on.

> layer 2: com.foo and com.bar at 2
> --------------------
> module com.bar {//version2
>
>      exports com.bar;
> }
>
> -------------
>
> //Bar.java
>
> packagecom.bar;
>
> public classBar {
>      publicString bar(){return"bar2";}
> }
>
> -------------
>
> module com.foo {
>          requires com.baz;
>
>          exports com.foo;
>
> }
>
> -------------
>
> Foo.java
>
> packagecom.foo;
>
> importcom.bar.Bar;
> importcom.baz.Baz;
>
> public classMain {
>      public static voidmain(String[] args) {
>          System.out.println(newBaz().baz());
>          System.out.println(newBar().bar());
>      }
> }

Foo.java should not compile. 'import com.bar.Bar' names a type that is 
inaccessible from module foo. This makes the rest of the scenario moot.

> public classTest {
>      public static voidmain(String[] args)throwsException {
>          ModuleFinder finder1 = ModuleFinder.of(Paths.get("mods1"));
>          Configuration cfg1 = Configuration.resolve(finder1, Layer.boot(),ModuleFinder.empty(),"com.bar","com.baz");
>
>          ModuleClassLoader cl1 =newModuleClassLoader(cfg1);
>          Layer layer1 = Layer.create(cfg1, m -> cl1);
>
>          ModuleFinder finder2 = ModuleFinder.of(Paths.get("mods2"));
>          Configuration cfg2 = Configuration.resolve(finder2, layer1,ModuleFinder.empty(),"com.bar","com.foo");
>
>          ModuleClassLoader cl2 =newModuleClassLoader(cl1,cfg2);
>          Layer layer2 = Layer.create(cfg2, m -> cl2);
>
>
>
>          Module foo = layer2.findModule("com.foo").get();
>          Module bar2 = layer2.findModule("com.bar").get();
>
>          Module bar1 = layer1.findModule("com.bar").get();
>
>          ClassLoader fooModuleLoader = layer2.findLoader("com.foo");
>          Class<?> mainClass = fooModuleLoader.loadClass("com.foo.Main");
>
>          Test.class.getModule().addReads(mainClass.getModule());
>          Method mainMethod = mainClass.getMethod("main", String[].class);
>
>          mainMethod.invoke(null, (Object)newString[0]);
>      }
>
> }
>
> Result:
>
> bar1
> bar2
>
> As you can see com.fooreads com.bar at 2 without reflection.
>
> I say this is puzzling since with almost the equivalent code I get another result. If you want I can show for you in another post.

It is puzzling. By specifying com.bar at 2 as one of the root modules in 
cfg2, you have managed to get layer2's loader to load the class 
com.bar.Bar from com.bar at 2. And code in module foo can access that 
class, despite module foo not reading any com.bar module.

Even though the main class in Foo.java should not have compiled, it 
would have been possible to produce class com.foo.Main by other means, 
and the module system should be more resilient in the face of such 
inconsistent separate compilation. We'll have to debug this.

Alex


More information about the jigsaw-dev mailing list