question on exports to

Jochen Theodorou blackdrag at gmx.org
Wed Jun 1 00:09:00 UTC 2016



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


More information about the jigsaw-dev mailing list