| /* | |
| * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /* | |
| * @test | |
| * @bug 8013527 | |
| * @run testng/othervm ChainedLookupTest | |
| * @summary Test MethodHandles.lookup method to produce the Lookup object with | |
| * proper lookup class if invoked through reflection and method handle. | |
| */ | |
| import java.lang.invoke.*; | |
| import java.lang.invoke.MethodHandles.Lookup; | |
| import java.lang.reflect.Method; | |
| import org.testng.annotations.Test; | |
| import static java.lang.invoke.MethodHandles.*; | |
| import static java.lang.invoke.MethodType.*; | |
| import static org.testng.Assert.*; | |
| public class ChainedLookupTest { | |
| /** | |
| * Direct call to MethodHandles::lookup | |
| */ | |
| @Test | |
| public void staticLookup() throws Throwable { | |
| Lookup lookup = lookup(); | |
| test(lookup, "Lookup produced via direct call to MethodHandles.lookup()"); | |
| } | |
| /** | |
| * Reflective Method::invoke on MethodHandles::lookup | |
| */ | |
| @Test | |
| public void methodInvoke() throws Throwable { | |
| Method m = MethodHandles.class.getMethod("lookup"); | |
| Lookup lookup = (Lookup) m.invoke(null); | |
| test(lookup, "Lookup produced via reflective call"); | |
| } | |
| /** | |
| * Invoke Method::invoke on MethodHandles::lookup via MethodHandle | |
| */ | |
| @Test | |
| public void methodInvokeViaMethodHandle() throws Throwable { | |
| Method m = MethodHandles.class.getMethod("lookup"); | |
| MethodHandle mh = lookup().findVirtual(Method.class, "invoke", | |
| methodType(Object.class, Object.class, Object[].class)); | |
| Lookup lookup = (Lookup)mh.invoke(m, (Object)null, (Object[])null); | |
| test(lookup, "Lookup produced via Method::invoke via MethodHandle"); | |
| } | |
| /** | |
| * Invoke MethodHandle on MethodHandles::lookup via Method::invoke | |
| */ | |
| // @Test | |
| public void methodHandleViaReflection() throws Throwable { | |
| MethodHandle MH_lookup = lookup().findStatic(MethodHandles.class, "lookup", methodType(Lookup.class)); | |
| Lookup lookup = (Lookup) MH_lookup.invokeExact(); | |
| Method m = MethodHandle.class.getMethod("invoke", Object[].class); | |
| // should this throw UnsupportedOperationException per MethodHandle::invoke spec? | |
| lookup = (Lookup)m.invoke(MH_lookup); | |
| test(lookup, "Lookup produced via MethodHandle::invoke via Method::invoke"); | |
| } | |
| /** | |
| * MethodHandle::invokeExact on MethodHandles::lookup | |
| */ | |
| @Test | |
| public void methodHandle() throws Throwable { | |
| MethodHandle MH_lookup = lookup().findStatic(MethodHandles.class, "lookup", methodType(Lookup.class)); | |
| Lookup lookup = (Lookup) MH_lookup.invokeExact(); | |
| test(lookup, "Lookup produced via MethodHandle"); | |
| } | |
| /** | |
| * MethodHandles::unreflect the reflective Method representing MethodHandles::lookup | |
| */ | |
| @Test | |
| public void unreflect() throws Throwable { | |
| MethodHandle MH_lookup = lookup().unreflect(MethodHandles.class.getMethod("lookup")); | |
| Lookup lookup = (Lookup) MH_lookup.invokeExact(); | |
| test(lookup, "Lookup produced via unreflect MethodHandle"); | |
| } | |
| /** | |
| * Use the Lookup object returned from MethodHandle::invokeExact on MethodHandles::lookup | |
| * to look up MethodHandle representing MethodHandles::lookup and then invoking it. | |
| */ | |
| @Test | |
| public void chainedMethodHandle() throws Throwable { | |
| MethodHandle MH_lookup = lookup().findStatic(MethodHandles.class, "lookup", methodType(Lookup.class)); | |
| Lookup lookup = (Lookup) MH_lookup.invokeExact(); | |
| MethodHandle MH_lookup2 = lookup.unreflect(MethodHandles.class.getMethod("lookup")); | |
| Lookup lookup2 = (Lookup) MH_lookup2.invokeExact(); | |
| test(lookup2, "Lookup produced via a chained call to MethodHandle"); | |
| } | |
| void test(Lookup lookup, String msg) throws Throwable { | |
| assertTrue(lookup.lookupClass() == ChainedLookupTest.class); | |
| assertTrue(lookup.hasFullPrivilegeAccess()); | |
| MethodHandle mh = lookup.findStatic(lookup.lookupClass(), "say", methodType(void.class, String.class)); | |
| mh.invokeExact(msg); | |
| } | |
| private static void say(String msg) { | |
| System.out.println(msg); | |
| } | |
| } | |