On 31.05.2016 23:23, Alex Buckley wrote:
On 5/31/2016 1:40 PM, Jochen Theodorou wrote:
named module GeneralInvoker, exports com.foo.gi.

package com.foo.gi;
public class TheInvoker{
   public static Object invoke(Object receiver, String name, Object..
args) {
     Method m = receiver.getClass().getDeclaredMethod(name,
toClass(args));
    return m.invoke(args);
   }
    .....
}

named module MyOtherLib, requires GeneralInvoker, no exports

package my.lib;
public class SomeClassOfTheLibrary {
   public void invokeBarOnArgument(Object x) {
     TheInvoker.invoke(x, "bar");
   }
   ....
}

(obviously this is just an outline, not real classes)

So if I see this right, then calling TheInvoker.invoke will fail,
because my.lib.SomeClassOfTheLibrary is not accessible by
com.foo.gi.TheInvoker. And am I right in that if MyOtherLib adds a
"export my.lib to GeneralInvoker", this will then work?

I assume you're talking about the body of
SomeClassOfTheLibrary::invokeBarOnArgument. The variable x could refer
to any object, so when TheInvoker::invoke gets hold of the reference (as
'receiver') and tries to invoke the 'bar' method, the invocation might
work. Depends whether the class of the referenced object is exported at
all.

yeah, sorry, that was not very clear.I mean that body, yes. Let x.class be any exported class MyOtherLib can read, or any class of MyOtherLib itself. Important here are two variants: (a) MyOtherLib does not export anything, (b) MyOtherLib exports my.lib to GeneralInvoker

My expectation would be for
Case (a) to fail for all classes of MyOtherLib and to fail for all classes from any Module GeneralInvoker does not have declared to require. Because I am under the impression, that just having module x somewhere in the system does imply readability for module y, only if they have a (transitive) exports-requires relationship (ignoring the service loader part here).

And for case (b) to work for all classes of MyOtherLib from my.lib, plus anything MyOtherLib can read.

Now some advanced questions ;)

assuming MyOtherLib also requires YetAnotherLib and has the exports-to
in the module descriptor... does it automatically imply readability For
GeneralInvoker on YetAnotherLib (only exported parts of course)?

Assuming this is not the case... can I use Module#addReads, with the
caller being from GeneralInvoker and the other Module being
YetAnotherLib, to create that readability?

Accessibility is a two-part check: i) does the accessing module read the
accessed module, and ii) does the accessed module export the right
package to at least the accessing module?

When you use the Core Reflection API, the answer to (i) is always "yes".
You never need to call Module::addReads. That is, when code in module M
manipulates a Class/Field/Method object, it's as if M reads whichever
module holds <<the class corresponding to the Class object>>/<<the class
declaring the field corresponding to the Field object>>/<<the class
declaring the method corresponding to the Executable object>>. The
accessibility question depends solely on (ii) -- whether that module
exports the right package to at least M.

ok. I kind of see that as a yes to my cases (a) and (b) above.

And even more difficult:

Assuming TheInvoker spawns a new class loader and a class within that to
do the actual method invocation. So far I assume the module of that
class would the unnamed module. As such I have access to the exports of
MyOtherLib and YetAnotherLib.

The class in the new loader is indeed in the unnamed module of that
loader. That unnamed module can certainly read the module MyOtherLib,
but I'm confused why you say "the exports of MyOtherLib" since you said
MyOtherLib has no exports.

yeah sorry... I was assuming a "export my.lib to GeneralInvoker" in MyOtherLib being present from here on

But how do I establish that class to be able to access
my.lib.SomeClassOfTheLibrary?

SomeClassOfTheLibrary has to grant the access.

I would have assumed Layers can do it, but I don't see how the API gives
me that. Having another exports-to in the module descriptor of
MyOtherLib will I think not work, since even if I define a naming
convention, this module does not exist at compile time.

Or should I trick Java by creating a dummy module with a certain name,
that MyOtherLib can export-to, but is used at compile time only?

Here I might be able to use Layer to define my module... unless the JVM
expects that module to exists7find when it loads MyOtherLib, in which
case I am stuck again.

So what am I missing or is this final part really not possible?

I think you're trying to do the same thing as Nashorn -- spin dynamic
modules with privileged access to framework internals. For now , I
recommend looking at Sundar's mail today on "RFR 8158131: Nashorn should
not use jdk.internal.module.Modules API". We plan to write up the
techniques because they're useful for all frameworks.

they are indeed.. but the cases differ in several points. Does Nashorn now support precompiled javascript code, that is in a named module as java style class? Because that is what MyOtherLib translates to. The difference is especially that I can have other libraries depending on MyOtherLib. Well, in my example it does not really make sense, since I did not define any exports, besides the exports-to for the framework. But I could... and that would maybe have been part of an expanded scenario in later mails ;)

The mail you mentioned is of limited use for me. It is a patch to enable something similar to what I want, yes, but on code I don't know using an API I have yet to fully understand. So I can see why they have the runtime generated module manipulator. I can see how

+    static Module createModuleTrusted(final Layer parent, final 
ModuleDescriptor descriptor, final ClassLoader loader) {
+        final String mn = descriptor.name();
+
+        final ModuleReference mref = new ModuleReference(descriptor, null, () 
-> {
+            IOException ioe = new IOException("<dynamic module>");
+            throw new UncheckedIOException(ioe);
+        });
+
+        final ModuleFinder finder = new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                if (name.equals(mn)) {
+                    return Optional.of(mref);
+                } else {
+                    return Optional.empty();
+                }
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return Set.of(mref);
+            }
+        };
+
+        final Configuration cf = parent.configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of(mn));
+
+        final PrivilegedAction<Layer> pa = () -> parent.defineModules(cf, name 
-> loader);
+        final Layer layer = AccessController.doPrivileged(pa, 
CREATE_AND_GET_LOADER_ACC_CTXT);
+
+        final Module m = layer.findModule(mn).get();
+        assert m.getLayer() == layer;
+
+        return m;
+    }

is code for a dynamic module. But it does not mean I understand all the parts related to exports-to for example. And then there is the part of the boot layer... Why can they be sure it is the right layer? Translated to my example.. what if MyOtherLib is a dynamic module, for which I need to create bytecode at runtime, being able to access the dynamic module internals... if I do that using layers for both, boot is surely not the right layer for the accessor. And as for the Module API itself.

bye Jochen

Reply via email to