Gradle not working on Jigsaw

Jochen Theodorou blackdrag at gmx.org
Fri Oct 21 09:08:37 UTC 2016



On 20.10.2016 16:14, Alan Bateman wrote:
> On 20/10/2016 14:48, Jochen Theodorou wrote:
>
>> :
>>
>> I still wish you had at least not included protected members. Sure,
>> protected is not public and protected is always a pain in the butt, I
>> still fail to comprehend the logic that a class can extend a class
>> from another module and then use the protected methods of the super
>> class, but setAccessible is not allowed to be used to gain access to
>> it from anywhere but that same class.
> This might appear to be an anomaly but remember you don't have the
> receiver at this point. You could have setAccessible silently fail so
> that the access check happens at newInstance/invoke/get/put but I don't
> see anyone being happy with that. That said, if you are using core
> reflection to access a protected member in the same package or super
> type then you don't need setAccessible in the first place as the access
> check should succeed (there have been issues with protected members that
> Peter has recently fixed in jdk9/dev, I don't know if you've run into
> that).

I wrote "same class" and thought same class and subclasses... my bad. 
Anyway, I am aware of how it works, the problem is that shi... caller 
sensitivity. If you work with classic reflection and have a central 
space for these kind of actions (for example because that had not really 
been caller sensitive before) you get into trouble now.

And another example...

Module A:
package a
class X {
    protected void foo(){}
}

unnamed Module:
package u
class Y extends X{
    public void bar(){ foo() }
}

How am I supposed to realize the call to foo using a runtime based on 
classic reflection? I have only one chance, and that is to have the 
actual Method.invokeMethod call at the callsite of foo(). If I do not do 
that, I have other frames in between and then @CallerSensitive will see 
the "wrong" intermediate frames and assume the call is not made from a 
class that actually has access. So I have about 5 frames of my runtime 
that will be in the way to realize this call.

Even with MethodHandle I can fall into this trap, if frames of my 
runtime get in the way. For example to realize dynamic typing I will not 
be able to do the actual method selection from bootstrap. I will do it 
by calling a method from my runtime, which then sets and calls the 
target. Subsequent calls will be without a frame of my runtime, but 
since the first call will fail, this does not matter. Also I would have 
to investigate but I think if you do a exception catching handle you may 
still get a frame of yours in. The only reason we can work around this 
with handles is, because Y will give a "I sell my soul to you" lookup 
object to the runtime.

And if you thought that is the worst, nope... Mix Closure in there and 
it gets a lot worse:

unnamed Module:
package u
class Y extends X{
    public void bar(){ def cl = {foo()}; cl() }
}

Now there will be 5 frames to Closure#call, one to doCall and another 7 
to the actual foo. And even though the exact class sunclassing Closure 
that is used to realize the call will be an inner class of Y, that does 
not mean I will automatically have a bridge method available. Such a 
method was simply not required before. And believe me, that is still not 
the worst. I have not started on Groovy builders yet....

To say it blunt: #AwkwardStrongEncapsulation prevents classic Groovy 
from calling protected methods properly... even if we did the java rules 
for protected.

It means there will be older Groovy programs, that will simply no longer 
run even with an updated version of the Groovy runtime. And I am not 
sure if we even *can* fix this. #AwkwardStrongEncapsulation is simply 
not including the concept of a runtime doing calls to protected methods. 
And just to be clear: trySetAccessible wouldn't help here either.

>> could be Groovy 2.4.7, that kind of error is fixed in  2.4.8... once
>> it is released, which we are currently working on. Because 2.4.7
>> assumes either all of the class can be made accessible or none. And
>> that is not true with #AwkwardStrongEncapsulation anymore. Which also
>> means meta class creation will take a lot longer, since we now cannot
>> use the array-taking setAccessible method in all cases anymore. Would
>> have been nice to have a version of setAccessible that just makes
>> accessible what is allowed and maybe reports back for those that are
>> not allowed.
> A trySetAccessible is possible although a @CS variant of accessCheck
> (like in MH.Lookup) might be more general. I think we need to be
> cautious about adding APIs here and so would be interesting to get some
> performance data here (I don't think I've seen the bulk setAccessible
> used very often, it's almost always the instance method).

well, we changed it exactly because the bulk variant is faster. It might 
be not much difference. Bunt if you have to create a few thousand meta 
classes, it makes a difference. And as stated above, a @CS variant will 
get us nowhere. I don't know why all the JDK people seem to think that 
@CS saves the world...

bye Jochen


More information about the jigsaw-dev mailing list