RFR: 8009411 : getMethods should not inherit static methods from interfaces

Joel Borggrén-Franck joel.franck at oracle.com
Fri Sep 13 13:38:30 UTC 2013


On Sep 13, 2013, at 3:18 PM, Peter Levart <peter.levart at gmail.com> wrote:

> On 09/13/2013 02:55 PM, Joel Borggrén-Franck wrote:
>> Hi Peter,
>> 
>> Interesting case, thanks for the testing.
>> 
>> On Sep 13, 2013, at 1:15 PM, Peter Levart <peter.levart at gmail.com> wrote:
>> 
>>> On 09/13/2013 12:18 PM, Peter Levart wrote:
>>>> The C.class.getMethods() returns a 1 element array containing A.m(), but C.class.getMethod("m") throws NoSuchMethodException.
>>>> 
>>>> This seems inconsistent, but it's a corner case that can only happen with separate compilation.
>>> Sorry Joel, I must have tested the unpatched code for C.class.getMethods(). In is in fact consistent with C.calss.getMethod("m"). Both calls don't return the A.m() method. in getMethod("m") case the recursion is stoped when B.m() static method is encountered and in getMethods() case the inherited method A.m() is removed from inheritedMethods array by the following in privateGetPublicMethods():
>>> 
>>>        // Filter out all local methods from inherited ones
>>>        for (int i = 0; i < methods.length(); i++) {
>>>            Method m = methods.get(i);
>>>            inheritedMethods.removeByNameAndSignature(m);
>>>        }
>>> 
>>> ...when collecting B's methods...
>>> 
>>> But the question remains whether A.m() should be seen by invokeinterface C.m() in spite of the fact that there is static B.m() in between and whether reflection should follow that.
>> I can't see any reason why an invokeinterface C.m() should not find a default method just because there is a static method with the same name and sig "in between". However the separate compilation setup required to arrange this is non-trivial in itself :)
> 
> It is non-trivial to arrange in a unit test. See the following for one possible trick:
> 
> http://cr.openjdk.java.net/~plevart/jdk8-tl/AnnotationType/webrev.05/test/java/lang/annotation/AnnotationType/AnnotationTypeRuntimeAssumptionTest.java.html
> 
> It's expectable that such situations will arise in practice. interface A can be a part of a vendor X library that's adding default methods in a new release, for example, and B & C can be part of a vendor Y app that is using the library...

I fully agree this will most probably occur in practice. But the situation is more complicated for an invoke, since there must have been a A.m() present when C was compiled in order to have an invokeinterface to be there in the first place. Just adding a default to A won't trigger this since there won't be an invokeinterface C.m().

Something like this might do:

Compile A { void m(); }, B {} and C {} together.
Compile A { } B { static m()} together
Compile A { default m(); }

Do you have a preference for how we should do this?

cheers
/Joel


More information about the core-libs-dev mailing list