On Sep 13, 2013, at 3:18 PM, Peter Levart <peter.lev...@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.lev...@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