--- old/test/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java 2016-10-04 10:21:55.674625436 +0200 +++ new/test/java/lang/reflect/DefaultMethodMembers/FilterNotMostSpecific.java 2016-10-04 10:21:55.589624986 +0200 @@ -36,9 +36,8 @@ import java.util.List; import java.util.Map; import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -55,7 +54,7 @@ for (MethodDesc expected : expectedMethods) { if (expected.isGetMethodReturn()) { try { - Method m = iface.getMethod(expected.name()); + Method m = iface.getMethod(expected.name(), expected.parameterTypes()); if (!assertMatch(expected, m)) fail(failMsg(expected, m, iface)); else @@ -72,26 +71,18 @@ public void testGetMethods(Class iface) { List foundMethods = filterObjectMethods(iface.getMethods()); MethodDesc[] expectedMethods = iface.getAnnotationsByType(MethodDesc.class); - Set used = new HashSet<>(); for (MethodDesc expected : expectedMethods) { boolean found = false; - for (Method m : foundMethods) { - if (used.contains(m)) - continue; - - if(expected.name().equals(m.getName()) && - expected.declaringClass() ==m.getDeclaringClass()) { - + if (assertMatch(expected, m)) { found = true; - assertMatch(expected, m); - used.add(m); break; } } - if (! found) - fail("On: "+ iface +"\nDid not find " + toMethodString(expected) + " among " + foundMethods); + if (!found) + fail("On: "+ iface +"\nDid not find " + toMethodString(expected) + + " among " + foundMethods); } assertEquals(foundMethods.size(), expectedMethods.length, "\non: " + iface + @@ -104,6 +95,11 @@ return false; if (expected.declaringClass() != m.getDeclaringClass()) return false; + if (!Arrays.equals(expected.parameterTypes(), m.getParameterTypes())) + return false; + if (expected.returnType() != NotSpecified.class && + expected.returnType() != m.getReturnType()) + return false; if (expected.kind() == MethodKind.ABSTRACT) assertTrue(Modifier.isAbstract(m.getModifiers()), m + " should be ABSTRACT"); @@ -128,8 +124,13 @@ } private String toMethodString(MethodDesc m) { - return m.declaringClass().getSimpleName().toString() + "." + - m.name() + "()"; + return (m.returnType() != NotSpecified.class + ? m.returnType().getSimpleName() + " " + : "") + + m.declaringClass().getSimpleName().toString() + "." + + m.name() + Stream.of(m.parameterTypes()) + .map(cl -> cl.getSimpleName()) + .collect(Collectors.joining(", ", "(", ")")); } private List toMethodStrings(MethodDesc[] m) { @@ -142,11 +143,16 @@ @Repeatable(MethodDescs.class) public @interface MethodDesc { String name(); + Class returnType() default NotSpecified.class; + Class[] parameterTypes() default {}; Class declaringClass(); MethodKind kind() default MethodKind.ABSTRACT; boolean isGetMethodReturn() default false; } + // special type marking a not-specified return type in @MethodDesc + interface NotSpecified {} + @Retention(RetentionPolicy.RUNTIME) public @interface MethodDescs { MethodDesc[] value(); @@ -172,22 +178,18 @@ @MethodDesc(name="nonDefault", declaringClass=Jbis.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=I.class) interface P2 extends Jbis, Jprim {} @MethodDesc(name="nonDefault", declaringClass=Jbis.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=I.class) interface P3 extends Jbis, Jprim, I {} - @MethodDesc(name="nonDefault", declaringClass=I.class, + @MethodDesc(name="nonDefault", declaringClass=J.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=J.class) interface P4 extends I, J {} @MethodDesc(name="nonDefault", declaringClass=J.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=I.class) interface P5 extends J, I {} @MethodDesc(name="nonDefault", declaringClass=J.class, @@ -198,14 +200,12 @@ isGetMethodReturn=true) interface K1M extends J { void nonDefault(); } - @MethodDesc(name="nonDefault", declaringClass=I.class, - isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=J.class) - interface K2 extends I, J {} + @MethodDesc(name="nonDefault", declaringClass=J.class, + isGetMethodReturn=true) + interface K2 extends I, J {} @MethodDesc(name="nonDefault", declaringClass=J.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=I.class) interface K2O extends J, I {} @MethodDesc(name="nonDefault", declaringClass=K2M.class, @@ -244,21 +244,18 @@ @MethodDesc(name="isDefault", declaringClass=M.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) @MethodDesc(name="nonDefault", declaringClass=M.class, isGetMethodReturn=true) interface N2 extends M, L {} @MethodDesc(name="isDefault", declaringClass=M.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="nonDefault", declaringClass=M.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) interface N22 extends L, M {} @MethodDesc(name="isDefault", declaringClass=N2D.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) @MethodDesc(name="nonDefault", declaringClass=M.class, isGetMethodReturn=true) interface N2D extends M, L { default void isDefault() {}} @@ -277,48 +274,36 @@ @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface O1 extends L, M, N2DN {} @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface O2 extends M, N2DN, L {} @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class) @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) interface O3 extends N2DN, L, M {} @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) abstract class C1 implements L, M, N2DN {} @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) abstract class C2 implements M, N2DN, L {} @MethodDesc(name="isDefault", declaringClass=N2DN.class, kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class) @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) abstract class C3 implements N2DN, L, M {} @@ -345,88 +330,54 @@ @MethodDesc(name="isDefault", declaringClass=R1.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R1 extends L, M, N2DN { void isDefault(); } @MethodDesc(name="isDefault", declaringClass=R2.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R2 extends M, N2DN, L { void isDefault(); } @MethodDesc(name="isDefault", declaringClass=R3.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class) @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) interface R3 extends N2DN, L, M { void isDefault(); } - // this one is strange but logical, getMethod finds N2DN first, which is - // default but not the most specific - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=R1.class) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="isDefault", declaringClass=R1.class, + isGetMethodReturn=true) + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R4 extends L, M, N2DN, R1 {} - // this one is strange but logical, getMethod finds N2DN first, which is - // default but not the most specific - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=R2.class) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class, + @MethodDesc(name="isDefault", declaringClass=R2.class, + isGetMethodReturn=true) + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R5 extends M, N2DN, R2, L {} - // this one is strange but logical, getMethod finds N2DN first, which is - // default but not the most specific - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=R3.class) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class) + @MethodDesc(name="isDefault", declaringClass=R3.class, + isGetMethodReturn=true) @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) interface R6 extends N2DN, R3, L, M {} - // the following three finds the "right" one @MethodDesc(name="isDefault", declaringClass=R1.class, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT) - @MethodDesc(name="nonDefault", declaringClass=L.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=M.class) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R7 extends L, M, R1, N2DN {} @MethodDesc(name="isDefault", declaringClass=R2.class, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class, + @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=N2DN.class) interface R8 extends M, R2, N2DN, L {} @MethodDesc(name="isDefault", declaringClass=R3.class, isGetMethodReturn=true) - @MethodDesc(name="isDefault", declaringClass=N2DN.class, - kind=MethodKind.DEFAULT) - @MethodDesc(name="nonDefault", declaringClass=L.class) - @MethodDesc(name="nonDefault", declaringClass=M.class) @MethodDesc(name="nonDefault", declaringClass=N2DN.class, isGetMethodReturn=true) interface R9 extends R3, N2DN, L, M {} @@ -445,51 +396,40 @@ interface Z3 extends Z2, Z1 { void z(); } - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z3.class) + @MethodDesc(name="z", declaringClass=Z3.class, + isGetMethodReturn = true) interface Z41 extends Z1, Z2, Z3 { } - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z3.class) + @MethodDesc(name="z", declaringClass=Z3.class, + isGetMethodReturn = true) interface Z42 extends Z2, Z3, Z1 { } @MethodDesc(name="z", declaringClass=Z3.class, - isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT) + isGetMethodReturn = true) interface Z43 extends Z3, Z1, Z2 { } - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z3.class) + @MethodDesc(name="z", declaringClass=Z3.class, + isGetMethodReturn = true) abstract class ZC41 implements Z1, Z2, Z3 { } - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z3.class) + @MethodDesc(name="z", declaringClass=Z3.class, + isGetMethodReturn = true) abstract class ZC42 implements Z2, Z3, Z1 { } @MethodDesc(name="z", declaringClass=Z3.class, - isGetMethodReturn=true) - @MethodDesc(name="z", declaringClass=Z2.class, - kind=MethodKind.DEFAULT) + isGetMethodReturn = true) abstract class ZC43 implements Z3, Z1, Z2 { } // More reabstraction + concretization interface X1 { default void x() {} } interface X2 extends X1 { void x(); } - @MethodDesc(name="x", declaringClass=X1.class, - kind=MethodKind.DEFAULT, isGetMethodReturn=true) - @MethodDesc(name="x", declaringClass=X2.class) + @MethodDesc(name="x", declaringClass=X2.class, + isGetMethodReturn=true) interface X31 extends X1, X2 {} @MethodDesc(name="x", declaringClass=X2.class, isGetMethodReturn=true) - @MethodDesc(name="x", declaringClass=X1.class, - kind=MethodKind.DEFAULT) interface X32 extends X2, X1 {} @MethodDesc(name="x", declaringClass=X3.class, @@ -524,85 +464,107 @@ interface K extends I, J { void nonDefault(); } - @MethodDesc(name="nonDefault", declaringClass=I.class, + @MethodDesc(name="nonDefault", declaringClass=K.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=J.class) - @MethodDesc(name="nonDefault", declaringClass=K.class) abstract class ZZ1 implements I, J, K {} - @MethodDesc(name="nonDefault", declaringClass=I.class, + @MethodDesc(name="nonDefault", declaringClass=K.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=J.class) - @MethodDesc(name="nonDefault", declaringClass=K.class) abstract class ZZ2 extends ZZ1 implements K, I, J {} - @MethodDesc(name="nonDefault", declaringClass=I.class, + @MethodDesc(name="nonDefault", declaringClass=K.class, isGetMethodReturn=true) - @MethodDesc(name="nonDefault", declaringClass=J.class) - @MethodDesc(name="nonDefault", declaringClass=K.class) abstract class ZZ3 extends ZZ2 implements J, K, I {} - // bridges - interface B1A { Object m(); } - interface B1B extends B1A { Map m(); } - - @MethodDesc(name="m", declaringClass=B1C.class, - isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=B1C.class, - kind=MethodKind.DEFAULT) - @MethodDesc(name="m", declaringClass=B1C.class, - kind=MethodKind.DEFAULT) - interface B1C extends B1B { HashMap m(); } - - @MethodDesc(name="m", declaringClass=B2.class, - isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=B2.class, - kind=MethodKind.DEFAULT) - @MethodDesc(name="m", declaringClass=B2.class, - kind=MethodKind.DEFAULT) - interface B2 extends B1C { HashMap m(); } - - @MethodDesc(name="m", declaringClass=B2.class, //HahsMap - isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=B2.class, //Map - kind=MethodKind.DEFAULT) - @MethodDesc(name="m", declaringClass=B2.class, //Object - kind=MethodKind.DEFAULT) - interface B3A extends B2, B1A {} - - // this one is funny since HashMap isn't a bridge thus not a default - @MethodDesc(name="m", declaringClass=B2.class, //HashMap - isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=B2.class, //Map - kind=MethodKind.DEFAULT) - @MethodDesc(name="m", declaringClass=B2.class, //Object - kind=MethodKind.DEFAULT) - @MethodDesc(name="m", declaringClass=B1C.class) //HashMap - interface B3B extends B2, B1C {} + // bridges... + + interface B1 { Object m(); } + interface B2A extends B1 { Map m(); } + interface B2B extends B1 { HashMap m(); } + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B3A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B3A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass=B3A.class, + isGetMethodReturn=true) + interface B3A extends B2A { HashMap m(); } + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class, + isGetMethodReturn=true) + interface B4A extends B3A { HashMap m(); } + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class, + isGetMethodReturn=true) + interface B5A2 extends B4A, B1 {} + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class, + isGetMethodReturn=true) + interface B5A4A extends B4A, B3A {} + + // ... + most specific return type for getMethod from two unrelated interfaces + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B2A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Object.class, declaringClass=B2B.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B2A.class) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass=B2B.class, + isGetMethodReturn=true) + interface B3AB extends B2A, B2B {} + + @MethodDesc(name="m", returnType=Object.class, declaringClass=B2A.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Object.class, declaringClass=B2B.class, + kind = MethodKind.DEFAULT) + @MethodDesc(name="m", returnType=Map.class, declaringClass=B2A.class) + @MethodDesc(name="m", returnType=HashMap.class, declaringClass=B2B.class, + isGetMethodReturn=true) + interface B3BA extends B2B, B2A {} // same name different params type interface A1 { void m(); void m(int i); void m(int i, int j); } interface A2A extends A1 { void m(); void m(int i); void m(int i, int j); } interface A2B extends A1 { void m(); void m(int i); default void m(int i, int j) {} } - @MethodDesc(name="m", declaringClass=A1.class, + @MethodDesc(name="m", parameterTypes = {}, declaringClass=A2A.class, + isGetMethodReturn=true) + @MethodDesc(name="m", parameterTypes = {int.class}, declaringClass=A2A.class, + isGetMethodReturn=true) + @MethodDesc(name="m", parameterTypes = {int.class, int.class}, declaringClass=A2A.class, isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=A1.class) - @MethodDesc(name="m", declaringClass=A1.class) - @MethodDesc(name="m", declaringClass=A2A.class) - @MethodDesc(name="m", declaringClass=A2A.class) - @MethodDesc(name="m", declaringClass=A2A.class) interface A3A extends A1, A2A {} - @MethodDesc(name="m", declaringClass=A1.class, + @MethodDesc(name="m", parameterTypes = {}, declaringClass=A2B.class, + isGetMethodReturn=true) + @MethodDesc(name="m", parameterTypes = {int.class}, declaringClass=A2B.class, isGetMethodReturn=true) - @MethodDesc(name="m", declaringClass=A1.class) - @MethodDesc(name="m", declaringClass=A2B.class) - @MethodDesc(name="m", declaringClass=A2B.class) - @MethodDesc(name="m", declaringClass=A2B.class, - kind=MethodKind.DEFAULT) + @MethodDesc(name="m", parameterTypes = {int.class, int.class}, declaringClass=A2B.class, + kind = MethodKind.DEFAULT, isGetMethodReturn=true) interface A3B extends A1, A2B {} + // method in directly implemented interface overrides interface method + // inherited by superclass + + interface E { void m(); } + interface F extends E { void m(); } + abstract class G implements E {} + + @MethodDesc(name="m", declaringClass=F.class, isGetMethodReturn=true) + abstract class H extends G implements F {} + @DataProvider public Object[][] getCases() { return CASES; } public static final Class[][] CASES = { @@ -680,12 +642,16 @@ { XC42.class }, { XC43.class }, - { B1C.class }, - { B2.class }, { B3A.class }, - { B3B.class }, + { B4A.class }, + { B5A2.class }, + { B5A4A.class }, + { B3AB.class }, + { B3BA.class }, { A3A.class }, { A3B.class }, + + { H.class }, }; }