--- old/src/share/classes/java/lang/Class.java 2013-09-26 16:41:41.066118962 +0200 +++ new/src/share/classes/java/lang/Class.java 2013-09-26 16:41:40.886118953 +0200 @@ -1555,6 +1555,10 @@ *

If this {@code Class} object represents a primitive type or void, * then the returned array has length 0. * + *

Static methods declared in superinterfaces of the class or interface + * represented by this {@code Class} object are not considered members of + * the class or interface. + * *

The elements in the returned array are not sorted and are not in any * particular order. * @@ -1713,6 +1717,10 @@ *

If this {@code Class} object represents an array type, then this * method does not find the {@code clone()} method. * + *

Static methods declared in superinterfaces of the class or interface + * represented by this {@code Class} object are not considered members of + * the class or interface. + * * @param name the name of the method * @param parameterTypes the list of parameters * @return the {@code Method} object that matches the specified @@ -2711,6 +2719,14 @@ } } + void addAllNonStatic(Method[] methods) { + for (Method candidate : methods) { + if (!Modifier.isStatic(candidate.getModifiers())) { + add(candidate); + } + } + } + int length() { return length; } @@ -2781,7 +2797,7 @@ MethodArray inheritedMethods = new MethodArray(); Class[] interfaces = getInterfaces(); for (int i = 0; i < interfaces.length; i++) { - inheritedMethods.addAll(interfaces[i].privateGetPublicMethods()); + inheritedMethods.addAllNonStatic(interfaces[i].privateGetPublicMethods()); } if (!isInterface()) { Class c = getSuperclass(); @@ -2910,9 +2926,9 @@ } // Search superinterfaces' methods Class[] interfaces = getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - Class c = interfaces[i]; - if ((res = c.getMethod0(name, parameterTypes)) != null) { + for (Class c : interfaces) { + if ((res = c.getMethod0(name, parameterTypes)) != null && + !Modifier.isStatic(res.getModifiers())) { return res; } } --- old/test/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java 2013-09-26 16:41:41.958119002 +0200 +++ new/test/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java 2013-09-26 16:41:41.762118993 +0200 @@ -44,30 +44,86 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; import org.testng.annotations.Test; import static helper.Mod.*; import static helper.Declared.*; import helper.Mod; + public class DefaultStaticInvokeTest { + // getMethods(): Make sure getMethods returns the expected methods. @Test(dataProvider = "testCasesAll", dataProviderClass = DefaultStaticTestData.class) public void testGetMethods(String testTarget, Object param) throws Exception { - // test the methods retrieved by getMethods() testMethods(ALL_METHODS, testTarget, param); } + + // getDeclaredMethods(): Make sure getDeclaredMethods returns the expected methods. @Test(dataProvider = "testCasesAll", dataProviderClass = DefaultStaticTestData.class) public void testGetDeclaredMethods(String testTarget, Object param) throws Exception { - // test the methods retrieved by getDeclaredMethods() testMethods(DECLARED_ONLY, testTarget, param); } + + // getMethod(): Make sure that getMethod finds all methods it should find. + @Test(dataProvider = "testCasesAll", + dataProviderClass = DefaultStaticTestData.class) + public void testGetMethod(String testTarget, Object param) + throws Exception { + + Class typeUnderTest = Class.forName(testTarget); + + MethodDesc[] descs = typeUnderTest.getAnnotationsByType(MethodDesc.class); + + for (MethodDesc desc : descs) { + assertTrue(isFoundByGetMethod(typeUnderTest, + desc.name(), + argTypes(param))); + } + } + + + // getMethod(): Make sure that getMethod does *not* find certain methods. + @Test(dataProvider = "testCasesAll", + dataProviderClass = DefaultStaticTestData.class) + public void testGetMethodSuperInterfaces(String testTarget, Object param) + throws Exception { + + // Make sure static methods in superinterfaces are not found (unless the type under + // test declares a static method with the same signature). + + Class typeUnderTest = Class.forName(testTarget); + + for (Class interfaze : typeUnderTest.getInterfaces()) { + + for (MethodDesc desc : interfaze.getAnnotationsByType(MethodDesc.class)) { + + boolean isStatic = desc.mod() == STATIC; + + boolean declaredInThisType = isMethodDeclared(typeUnderTest, + desc.name()); + + boolean expectedToBeFound = !isStatic || declaredInThisType; + + if (expectedToBeFound) + continue; // already tested in testGetMethod() + + assertFalse(isFoundByGetMethod(typeUnderTest, + desc.name(), + argTypes(param))); + } + } + } + + + // Method.invoke(): Make sure Method.invoke returns the expected value. @Test(dataProvider = "testCasesAll", dataProviderClass = DefaultStaticTestData.class) public void testMethodInvoke(String testTarget, Object param) @@ -78,11 +134,13 @@ // test the method retrieved by Class.getMethod(String, Object[]) for (MethodDesc toTest : expectedMethods) { String name = toTest.name(); - Method m = getTestMethod(typeUnderTest, name, param); + Method m = typeUnderTest.getMethod(name, argTypes(param)); testThisMethod(toTest, m, typeUnderTest, param); } } + + // MethodHandle.invoke(): Make sure MethodHandle.invoke returns the expected value. @Test(dataProvider = "testCasesAll", dataProviderClass = DefaultStaticTestData.class) public void testMethodHandleInvoke(String testTarget, Object param) @@ -116,6 +174,7 @@ } + // Lookup.findStatic / .findVirtual: Make sure IllegalAccessException is thrown as expected. @Test(dataProvider = "testClasses", dataProviderClass = DefaultStaticTestData.class) public void testIAE(String testTarget, Object param) @@ -128,7 +187,7 @@ String mName = toTest.name(); Mod mod = toTest.mod(); if (mod != STATIC && typeUnderTest.isInterface()) { - return; + continue; } Exception caught = null; try { @@ -136,10 +195,12 @@ } catch (Exception e) { caught = e; } - assertTrue(caught != null); + assertNotNull(caught); assertEquals(caught.getClass(), IllegalAccessException.class); } } + + private static final String[] OBJECT_METHOD_NAMES = { "equals", "hashCode", @@ -192,15 +253,15 @@ myMethods.put(mName, m); } } - assertEquals(expectedMethods.length, myMethods.size()); + + assertEquals(myMethods.size(), expectedMethods.length); for (MethodDesc toTest : expectedMethods) { String name = toTest.name(); - Method candidate = myMethods.get(name); + Method candidate = myMethods.remove(name); assertNotNull(candidate); - myMethods.remove(name); testThisMethod(toTest, candidate, typeUnderTest, param); @@ -210,6 +271,7 @@ assertTrue(myMethods.isEmpty()); } + private void testThisMethod(MethodDesc toTest, Method method, Class typeUnderTest, Object param) throws Exception { // Test modifiers, and invoke @@ -256,37 +318,52 @@ assertFalse(method.isDefault()); break; default: - assertFalse(true); //this should never happen + fail(); //this should never happen break; } } + + private boolean isMethodDeclared(Class type, String name) { + MethodDesc[] methDescs = type.getAnnotationsByType(MethodDesc.class); + for (MethodDesc desc : methDescs) { + if (desc.declared() == YES && desc.name().equals(name)) + return true; + } + return false; + } + + + private boolean isFoundByGetMethod(Class c, String method, Class... argTypes) { + try { + c.getMethod(method, argTypes); + return true; + } catch (NoSuchMethodException notFound) { + return false; + } + } + + + private Class[] argTypes(Object param) { + return param == null ? new Class[0] : new Class[] { Object.class }; + } + + private Object tryInvoke(Method m, Class receiverType, Object param) throws Exception { Object receiver = receiverType == null ? null : receiverType.newInstance(); - Object result = null; - if (param == null) { - result = m.invoke(receiver); - } else { - result = m.invoke(receiver, param); - } - return result; + Object[] args = param == null ? new Object[0] : new Object[] { param }; + return m.invoke(receiver, args); } - private Method getTestMethod(Class clazz, String methodName, Object param) - throws NoSuchMethodException { - Class[] paramsType = (param != null) - ? new Class[]{Object.class} - : new Class[]{}; - return clazz.getMethod(methodName, paramsType); - } private MethodHandle getTestMH(Class clazz, String methodName, Object param) throws Exception { return getTestMH(clazz, methodName, param, false); } + private MethodHandle getTestMH(Class clazz, String methodName, Object param, boolean isNegativeTest) throws Exception { --- old/test/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java 2013-09-26 16:41:42.702119038 +0200 +++ new/test/java/lang/reflect/DefaultStaticTest/DefaultStaticTestData.java 2013-09-26 16:41:42.506119025 +0200 @@ -172,7 +172,7 @@ @MethodDesc(name = "defaultMethod", retval = "TestIF8.TestClass8", mod = DEFAULT, declared = NO) class TestClass8 implements TestIF8 { -}; +} @MethodDesc(name = "defaultMethod", retval = "TestIF9.defaultMethod", mod = DEFAULT, declared = YES) interface TestIF9 extends TestIF1 { @@ -218,7 +218,6 @@ } @MethodDesc(name = "defaultMethod", retval = "TestIF12.defaultMethod", mod = DEFAULT, declared = YES) -@MethodDesc(name = "staticMethod", retval = "TestIF2.staticMethod", mod = STATIC, declared = NO) interface TestIF12 extends TestIF2 { default String defaultMethod() { @@ -299,7 +298,7 @@ @MethodDesc(name = "defaultMethod", retval = "TestIF16.defaultMethod", mod = DEFAULT, declared = NO) class TestClass16 implements TestIF16 { -}; +} @MethodDesc(name = "defaultMethod", retval = "TestIF17.defaultMethod", mod = DEFAULT, declared = YES) @MethodDesc(name = "staticMethod", retval = "TestIF17.staticMethod", mod = STATIC, declared = YES) @@ -318,6 +317,12 @@ class TestClass17 implements TestIF17 { } + +@MethodDesc(name = "defaultMethod", retval = "TestIF17.defaultMethod", mod = DEFAULT, declared = NO) +class TestClass18 extends TestClass17 { +} + + @Retention(RetentionPolicy.RUNTIME) @Repeatable(MethodDescs.class) @interface MethodDesc { @@ -332,6 +337,41 @@ MethodDesc[] value(); } +//Diamond Case for static method +@MethodDesc(name = "staticMethod", retval = "TestIF2A.staticMethod", mod = STATIC, declared = YES) +interface TestIF2A extends TestIF2 { + static String staticMethod() { + return "TestIF2A.staticMethod"; + } +} + +@MethodDesc(name = "method", retval = "", mod = ABSTRACT, declared = YES) +interface TestIF2B extends TestIF2 { + String method(); +} + +@MethodDesc(name = "method", retval = "", mod = ABSTRACT, declared = YES) +interface TestIF18 extends TestIF10, TestIF2A { + String method(); +} + +@MethodDesc(name = "method", retval = "", mod = ABSTRACT, declared = NO) +@MethodDesc(name = "defaultMethod", retval = "TestIF12.defaultMethod", mod = DEFAULT, declared = NO) +interface TestIF19 extends TestIF12, TestIF2B { +} + +@MethodDesc(name = "staticMethod", retval = "TestIF20.staticMethod", mod = STATIC, declared = YES) +@MethodDesc(name = "defaultMethod", retval = "TestIF12.defaultMethod", mod = DEFAULT, declared = NO) +interface TestIF20 extends TestIF12, TestIF2A { + static String staticMethod() { + return "TestIF20.staticMethod"; + } +} + +@MethodDesc(name = "method", retval = "", mod = ABSTRACT, declared = NO) +interface TestIF21 extends TestIF2A, TestIF2B { +} + public class DefaultStaticTestData { /** @@ -343,22 +383,23 @@ static Object[][] testClasses() { return new Object[][]{ {"TestClass1", null}, - //{"TestClass2", null}, @ignore due to JDK-8009411 + {"TestClass2", null}, {"TestClass3", null}, - //{"TestClass4", null}, @ignore due to JDK-8009411 - //{"TestClass5", null}, @ignore due to JDK-8009411 - //{"TestClass6", null}, @ignore due to JDK-8009411 + {"TestClass4", null}, + {"TestClass5", null}, + {"TestClass6", null}, {"TestClass7", "TestIF7.TestClass7"}, {"TestClass8", "TestIF8.TestClass8"}, {"TestClass9", null}, {"TestClass91", null}, - //{"TestClass11", null}, @ignore due to JDK-8009411 - //{"TestClass12", null}, @ignore due to JDK-8009411 + {"TestClass11", null}, + {"TestClass12", null}, {"TestClass13", null}, {"TestClass14", null}, {"TestClass15", null}, - {"TestClass16", null} - //{"TestClass17", null} @ignore due to JDK-8009411 + {"TestClass16", null}, + {"TestClass17", null}, + {"TestClass18", null}, }; } @@ -372,6 +413,8 @@ return new Object[][]{ {"TestIF1", null}, {"TestIF2", null}, + {"TestIF2A", null}, + {"TestIF2B", null}, {"TestIF3", null}, {"TestIF4", null}, {"TestIF5", null}, @@ -388,7 +431,12 @@ {"TestIF1D", null}, {"TestIF15", null}, {"TestIF16", null}, - {"TestIF17", null},}; + {"TestIF17", null}, + {"TestIF18", null}, + {"TestIF19", null}, + {"TestIF20", null}, + {"TestIF21", null}, + }; } @DataProvider