Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java
38828 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @summary Test locating and invoking default/static method that defined26* in interfaces and/or in inheritance27* @bug 718482628* @build helper.Mod helper.Declared DefaultStaticTestData29* @run testng DefaultStaticInvokeTest30* @author Yong Lu31*/3233import java.lang.invoke.MethodHandle;34import java.lang.invoke.MethodHandles;35import java.lang.invoke.MethodType;36import java.lang.reflect.Method;37import java.lang.reflect.Modifier;38import java.util.Arrays;39import java.util.HashMap;40import java.util.HashSet;4142import static org.testng.Assert.assertEquals;43import static org.testng.Assert.assertTrue;44import static org.testng.Assert.assertFalse;45import static org.testng.Assert.assertNotNull;46import static org.testng.Assert.fail;47import org.testng.annotations.Test;4849import static helper.Mod.*;50import static helper.Declared.*;51import helper.Mod;525354public class DefaultStaticInvokeTest {5556// getMethods(): Make sure getMethods returns the expected methods.57@Test(dataProvider = "testCasesAll",58dataProviderClass = DefaultStaticTestData.class)59public void testGetMethods(String testTarget, Object param)60throws Exception {61testMethods(ALL_METHODS, testTarget, param);62}636465// getDeclaredMethods(): Make sure getDeclaredMethods returns the expected methods.66@Test(dataProvider = "testCasesAll",67dataProviderClass = DefaultStaticTestData.class)68public void testGetDeclaredMethods(String testTarget, Object param)69throws Exception {70testMethods(DECLARED_ONLY, testTarget, param);71}727374// getMethod(): Make sure that getMethod finds all methods it should find.75@Test(dataProvider = "testCasesAll",76dataProviderClass = DefaultStaticTestData.class)77public void testGetMethod(String testTarget, Object param)78throws Exception {7980Class<?> typeUnderTest = Class.forName(testTarget);8182MethodDesc[] descs = typeUnderTest.getAnnotationsByType(MethodDesc.class);8384for (MethodDesc desc : descs) {85assertTrue(isFoundByGetMethod(typeUnderTest,86desc.name(),87argTypes(param)));88}89}909192// getMethod(): Make sure that getMethod does *not* find certain methods.93@Test(dataProvider = "testCasesAll",94dataProviderClass = DefaultStaticTestData.class)95public void testGetMethodSuperInterfaces(String testTarget, Object param)96throws Exception {9798// Make sure static methods in superinterfaces are not found (unless the type under99// test declares a static method with the same signature).100101Class<?> typeUnderTest = Class.forName(testTarget);102103for (Class<?> interfaze : typeUnderTest.getInterfaces()) {104105for (MethodDesc desc : interfaze.getAnnotationsByType(MethodDesc.class)) {106107boolean isStatic = desc.mod() == STATIC;108109boolean declaredInThisType = isMethodDeclared(typeUnderTest,110desc.name());111112boolean expectedToBeFound = !isStatic || declaredInThisType;113114if (expectedToBeFound)115continue; // already tested in testGetMethod()116117assertFalse(isFoundByGetMethod(typeUnderTest,118desc.name(),119argTypes(param)));120}121}122}123124125// Method.invoke(): Make sure Method.invoke returns the expected value.126@Test(dataProvider = "testCasesAll",127dataProviderClass = DefaultStaticTestData.class)128public void testMethodInvoke(String testTarget, Object param)129throws Exception {130Class<?> typeUnderTest = Class.forName(testTarget);131MethodDesc[] expectedMethods = typeUnderTest.getAnnotationsByType(MethodDesc.class);132133// test the method retrieved by Class.getMethod(String, Object[])134for (MethodDesc toTest : expectedMethods) {135String name = toTest.name();136Method m = typeUnderTest.getMethod(name, argTypes(param));137testThisMethod(toTest, m, typeUnderTest, param);138}139}140141142// MethodHandle.invoke(): Make sure MethodHandle.invoke returns the expected value.143@Test(dataProvider = "testCasesAll",144dataProviderClass = DefaultStaticTestData.class)145public void testMethodHandleInvoke(String testTarget, Object param)146throws Throwable {147Class<?> typeUnderTest = Class.forName(testTarget);148MethodDesc[] expectedMethods = typeUnderTest.getAnnotationsByType(MethodDesc.class);149150for (MethodDesc toTest : expectedMethods) {151String mName = toTest.name();152Mod mod = toTest.mod();153if (mod != STATIC && typeUnderTest.isInterface()) {154return;155}156157String result = null;158String expectedReturn = toTest.retval();159160MethodHandle methodHandle = getTestMH(typeUnderTest, mName, param);161if (mName.equals("staticMethod")) {162result = (param == null)163? (String) methodHandle.invoke()164: (String) methodHandle.invoke(param);165} else {166result = (param == null)167? (String) methodHandle.invoke(typeUnderTest.newInstance())168: (String) methodHandle.invoke(typeUnderTest.newInstance(), param);169}170171assertEquals(result, expectedReturn);172}173174}175176// Lookup.findStatic / .findVirtual: Make sure IllegalAccessException is thrown as expected.177@Test(dataProvider = "testClasses",178dataProviderClass = DefaultStaticTestData.class)179public void testIAE(String testTarget, Object param)180throws ClassNotFoundException {181182Class<?> typeUnderTest = Class.forName(testTarget);183MethodDesc[] expectedMethods = typeUnderTest.getAnnotationsByType(MethodDesc.class);184185for (MethodDesc toTest : expectedMethods) {186String mName = toTest.name();187Mod mod = toTest.mod();188if (mod != STATIC && typeUnderTest.isInterface()) {189continue;190}191Exception caught = null;192try {193getTestMH(typeUnderTest, mName, param, true);194} catch (Exception e) {195caught = e;196}197assertNotNull(caught);198assertEquals(caught.getClass(), IllegalAccessException.class);199}200}201202203private static final String[] OBJECT_METHOD_NAMES = {204"equals",205"hashCode",206"getClass",207"notify",208"notifyAll",209"toString",210"wait",211"wait",212"wait",};213private static final String LAMBDA_METHOD_NAMES = "lambda$";214private static final HashSet<String> OBJECT_NAMES = new HashSet<>(Arrays.asList(OBJECT_METHOD_NAMES));215private static final boolean DECLARED_ONLY = true;216private static final boolean ALL_METHODS = false;217218private void testMethods(boolean declaredOnly, String testTarget, Object param)219throws Exception {220Class<?> typeUnderTest = Class.forName(testTarget);221Method[] methods = declaredOnly222? typeUnderTest.getDeclaredMethods()223: typeUnderTest.getMethods();224225MethodDesc[] baseExpectedMethods = typeUnderTest.getAnnotationsByType(MethodDesc.class);226MethodDesc[] expectedMethods;227228// If only declared filter out non-declared from expected result229if (declaredOnly) {230int nonDeclared = 0;231for (MethodDesc desc : baseExpectedMethods) {232if (desc.declared() == NO) {233nonDeclared++;234}235}236expectedMethods = new MethodDesc[baseExpectedMethods.length - nonDeclared];237int i = 0;238for (MethodDesc desc : baseExpectedMethods) {239if (desc.declared() == YES) {240expectedMethods[i++] = desc;241}242}243} else {244expectedMethods = baseExpectedMethods;245}246247HashMap<String, Method> myMethods = new HashMap<>(methods.length);248for (Method m : methods) {249String mName = m.getName();250// don't add Object methods and method created from lambda expression251if ((!OBJECT_NAMES.contains(mName)) && (!mName.contains(LAMBDA_METHOD_NAMES))) {252myMethods.put(mName, m);253}254}255256assertEquals(myMethods.size(), expectedMethods.length);257258for (MethodDesc toTest : expectedMethods) {259260String name = toTest.name();261Method candidate = myMethods.remove(name);262263assertNotNull(candidate);264265testThisMethod(toTest, candidate, typeUnderTest, param);266267}268269// Should be no methods left since we remove all we expect to see270assertTrue(myMethods.isEmpty());271}272273274private void testThisMethod(MethodDesc toTest, Method method,275Class<?> typeUnderTest, Object param) throws Exception {276// Test modifiers, and invoke277Mod mod = toTest.mod();278String expectedReturn = toTest.retval();279switch (mod) {280case STATIC:281//assert candidate is static282assertTrue(Modifier.isStatic(method.getModifiers()));283assertFalse(method.isDefault());284285// Test invoke it286assertEquals(tryInvoke(method, null, param), expectedReturn);287break;288case DEFAULT:289// if typeUnderTest is a class then instantiate and invoke290if (!typeUnderTest.isInterface()) {291assertEquals(tryInvoke(292method,293typeUnderTest,294param),295expectedReturn);296}297298//assert candidate is default299assertFalse(Modifier.isStatic(method.getModifiers()));300assertTrue(method.isDefault());301break;302case REGULAR:303// if typeUnderTest must be a class304assertEquals(tryInvoke(305method,306typeUnderTest,307param),308expectedReturn);309310//assert candidate is neither default nor static311assertFalse(Modifier.isStatic(method.getModifiers()));312assertFalse(method.isDefault());313break;314case ABSTRACT:315//assert candidate is neither default nor static316assertFalse(Modifier.isStatic(method.getModifiers()));317assertFalse(method.isDefault());318break;319default:320fail(); //this should never happen321break;322}323324}325326327private boolean isMethodDeclared(Class<?> type, String name) {328MethodDesc[] methDescs = type.getAnnotationsByType(MethodDesc.class);329for (MethodDesc desc : methDescs) {330if (desc.declared() == YES && desc.name().equals(name))331return true;332}333return false;334}335336337private boolean isFoundByGetMethod(Class<?> c, String method, Class<?>... argTypes) {338try {339c.getMethod(method, argTypes);340return true;341} catch (NoSuchMethodException notFound) {342return false;343}344}345346347private Class<?>[] argTypes(Object param) {348return param == null ? new Class[0] : new Class[] { Object.class };349}350351352private Object tryInvoke(Method m, Class<?> receiverType, Object param)353throws Exception {354Object receiver = receiverType == null ? null : receiverType.newInstance();355Object[] args = param == null ? new Object[0] : new Object[] { param };356return m.invoke(receiver, args);357}358359360private MethodHandle getTestMH(Class clazz, String methodName, Object param)361throws Exception {362return getTestMH(clazz, methodName, param, false);363}364365366private MethodHandle getTestMH(Class clazz, String methodName,367Object param, boolean isNegativeTest)368throws Exception {369MethodType mType = (param != null)370? MethodType.genericMethodType(1)371: MethodType.methodType(String.class);372MethodHandles.Lookup lookup = MethodHandles.lookup();373if (!isNegativeTest) {374return methodName.equals("staticMethod")375? lookup.findStatic(clazz, methodName, mType)376: lookup.findVirtual(clazz, methodName, mType);377} else {378return methodName.equals("staticMethod")379? lookup.findVirtual(clazz, methodName, mType)380: lookup.findStatic(clazz, methodName, mType);381}382}383}384385386