question on exports to
Jochen Theodorou
blackdrag at gmx.org
Wed Jun 1 08:34:47 UTC 2016
On 01.06.2016 02:37, Alex Buckley wrote:
> On 5/31/2016 5:09 PM, Jochen Theodorou wrote:
>> 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).
>
> If x.class returns a class in module MyOtherLib, then since MyOtherLib
> does not export anything, code in module GeneralInvoker cannot
> instantiate the class with newInstance(), or access the class's fields
> with getField(..).get()/set(), or access the class's methods with
> getMethods(..).invoke().
>
> If x.class returns a class in some module other than MyOtherLib, then
> whether code in module GeneralInvoker can reflect over the class depends
> on whether the class is exported to GeneralInvoker.
>
> You mention module x having readability of module y only if they have a
> transitive exports-requires relationship ... but exports is nothing to
> do with readability. The two-sided relationship that matters is
> X-reads-Y + Y-exports-to-at-least-X, and what it matters for is
> accessibility, a higher level thing than readability. Have you watched
> my "Project Jigsaw: Under The Hood" video from JavaOne 2015?
now I have, and it points the exports-requires part out more clearly,
true. But you know, hearing something is one thing... understanding it
and then be able to integrate it in my own thoughts is something else.
And even if something is supposed to be easy, it not always is, because
your thoughts have been led astray by something else, or you are trying
to match that system against a totally different one, maybe even without
being aware of it. Anyway... it made me think, that I actually made an
early error...
MyOtherLib will require GeneralInvoker, because it is calling a method
from it. GeneralInvoker will export the package with the classes
MyOtherLib requires. So all fine here. But now I want GeneralInvoker to
be able to use classes form MyOtherLib, without GeneralInvoker knowing
MyOtherLib at compile time. That's where I came up with the exports-to.
But there is no requires in GeneralInvoker. Which then means to me this
will (a) not work and (b) adding a requires (which is not possible in my
scenario) would produce a circular dependency and fail again.
Then again you said: """
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.
"""
Which means the Core Reflection API has rights beyond what I described.
And the question to me is what GeneralInvoker has to do, to get similar
rights.... to for example not use the core reflection API, but its own,
runtime generated classes to do something similar. And that again would
lead me to believe GeneralInvoker has to call Module::addReads, on its
own module with the module of MyOtherLib as argument... and hope there
is no circular dependency check at this point. Well... actually that
addReads has to be for the part actually doing the invocation as well...
which leads me back to the problem of how to enable a dynamic named
module to read an "internal" API from a named module.
This now looks to me like this... GeneralInvoker will have to call
generalInvokerModule.addReads(myOtherLibModule), to enable to inspect
the classes from that library. It will then spawn a layer with a named
module, which contains the invocation code. This layerModule will
contain code to call layerModule.addReads(myOtherLibModule), so it can
access the classes in MyOtherLib if they are exported.... and since that
is not yet the case, I will have to cause MyOtherLib to call
myOtherLib.addExports("my.lib", layerModule).
Which still means I cannot replace reflection completely, since it does
not have to cause MyOtherLib to call myOtherLib.addExports("my.lib",
layerModule). Or it means I still lack understanding - which would not
surprise me at all.
bye Jochen
More information about the jigsaw-dev
mailing list