| /* |
| * Copyright (c) 2017, 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 8173898 |
| * @summary Basic test for checking filtering of reflection frames |
| * @run testng ReflectionFrames |
| */ |
| |
| import java.lang.StackWalker.StackFrame; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Method; |
| import java.lang.invoke.MethodHandle; |
| import java.lang.invoke.MethodHandles; |
| import java.lang.invoke.MethodHandles.Lookup; |
| import java.lang.invoke.MethodType; |
| import java.util.EnumSet; |
| import java.util.List; |
| import java.util.function.Supplier; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| import static java.lang.StackWalker.Option.*; |
| |
| import org.testng.annotations.DataProvider; |
| import org.testng.annotations.Test; |
| import static org.testng.Assert.*; |
| |
| public class ReflectionFrames { |
| final static boolean verbose = false; |
| |
| /** |
| * This test invokes new StackInspector() directly from |
| * the caller StackInspector.Caller.create method. |
| * It checks that the caller is StackInspector.Caller. |
| * It also checks the expected frames collected |
| * by walking the stack from the default StackInspector() |
| * constructor. |
| * This is done twice, once using a default StackWalker |
| * that hides reflection frames, once using a StackWalker |
| * configured to show reflection frames. |
| */ |
| @Test |
| public static void testNewStackInspector() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes new StackInspector() directly. |
| // No reflection frame should appear. |
| System.out.println("testNewStackInspector: create"); |
| |
| StackInspector obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes new StackInspector() directly. |
| // No reflection frame should appear. |
| System.out.println("testNewStackInspector: reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // a MethodHandle. |
| // The create method invokes new StackInspector() directly. |
| // No reflection frame should appear. |
| System.out.println("testNewStackInspector: handle"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes new StackInspector() directly. |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewStackInspector: create: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes new StackInspector() directly. |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewStackInspector: reflect: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // MethodHandle. |
| // The create method invokes new StackInspector() directly. |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewStackInspector: handle: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.NEW)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| // MethodHandle::invoke remains hidden |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewStackInspector")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| } |
| |
| /** |
| * This test invokes Constructor.newInstance() from |
| * the caller StackInspector.Caller.create method. |
| * It checks that the caller is StackInspector.Caller. |
| * It also checks the expected frames collected |
| * by walking the stack from the default StackInspector() |
| * constructor. |
| * This is done twice, once using a default StackWalker |
| * that hides reflection frames, once using a StackWalker |
| * configured to show reflection frames. |
| */ |
| @Test |
| public static void testConstructor() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes Constructor.newInstance(). |
| // No reflection frame should appear. |
| System.out.println("testConstructor: create"); |
| |
| StackInspector obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes Constructor.newInstance(). |
| // No reflection frame should appear. |
| System.out.println("testConstructor: reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // MethodHandle. |
| // The create method invokes Constructor.newInstance(). |
| // No reflection frame should appear. |
| System.out.println("testConstructor: handle"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes Constructor.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testConstructor: create: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes Constructor.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testConstructor: reflect: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // MethodHandle. |
| // The create method invokes Constructor.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testConstructor: handle: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.CONSTRUCTOR)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| // MethodHandle::invoke remains hidden |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testConstructor")); |
| assertEquals(obj.cls, StackInspector.Caller.class); |
| assertNotEquals(obj.filtered, 0); |
| } |
| |
| /** |
| * This test invokes StackInspector.class.newInstance() from |
| * the caller StackInspector.Caller.create method. Because |
| * Class.newInstance() is not considered as a |
| * reflection frame, the the caller returned by |
| * getCallerClass() should appear to be java.lang.Class |
| * and not StackInspector.Caller. |
| * It also checks the expected frames collected |
| * by walking the stack from the default StackInspector() |
| * constructor. |
| * This is done twice, once using a default StackWalker |
| * that hides reflection frames, once using a StackWalker |
| * configured to show reflection frames. |
| */ |
| @Test |
| public static void testNewInstance() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes StackInspector.class.newInstance(). |
| // No reflection frame should appear, except |
| // Class::newInstance which is not considered as |
| // a reflection frame. |
| System.out.println("testNewInstance: create"); |
| |
| StackInspector obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes StackInspector.class.newInstance(). |
| // No reflection frame should appear, except |
| // Class::newInstance which is not considered as |
| // a reflection frame. |
| System.out.println("testNewInstance: reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // reflection. |
| // The create method invokes StackInspector.class.newInstance(). |
| // No reflection frame should appear, except |
| // Class::newInstance which is not considered as |
| // a reflection frame. |
| System.out.println("testNewInstance: handle"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertEquals(obj.filtered, 0); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| // Calls the StackInspector.create method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The create method invokes StackInspector.class.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewInstance: create: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("create", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.reflect method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The reflect method invokes the create method through |
| // reflection. |
| // The create method invokes StackInspector.class.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewInstance: reflect: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("reflect", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| Method.class.getName() |
| +"::invoke", |
| StackInspector.Caller.class.getName() |
| +"::reflect", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertNotEquals(obj.filtered, 0); |
| |
| // Calls the StackInspector.handle method through reflection |
| // and check the frames collected in the StackInspector |
| // default constructor. |
| // The handle method invokes the create method using |
| // MethodHandle. |
| // The create method invokes StackInspector.class.newInstance(). |
| // We should see all reflection frames, except the |
| // jdk.internal.reflect frames which we are filtering |
| // out in StackInspector::filter. |
| System.out.println("testNewInstance: handle: show reflect"); |
| |
| obj = ((StackInspector)StackInspector.Caller.class |
| .getMethod("handle", How.class) |
| .invoke(null, How.CLASS)); |
| assertEquals(obj.collectedFrames, |
| List.of(StackInspector.class.getName() |
| +"::<init>", |
| Constructor.class.getName() |
| +"::newInstance", |
| Class.class.getName() |
| +"::newInstance", |
| StackInspector.Caller.class.getName() |
| +"::create", |
| // MethodHandle::invoke remains hidden |
| StackInspector.Caller.class.getName() |
| +"::handle", |
| Method.class.getName() |
| +"::invoke", |
| ReflectionFrames.class.getName() |
| +"::testNewInstance")); |
| |
| // Because Class.newInstance is not filtered, then the |
| // caller is Class.class |
| assertEquals(obj.cls, Class.class); |
| assertNotEquals(obj.filtered, 0); |
| } |
| |
| @Test |
| public static void testGetCaller() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| assertEquals(StackInspector.getCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), |
| ReflectionFrames.class); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| assertEquals(StackInspector.getCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), |
| ReflectionFrames.class); |
| } |
| |
| @Test |
| public static void testReflectCaller() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), |
| ReflectionFrames.class); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), |
| ReflectionFrames.class); |
| } |
| |
| @Test |
| public static void testSupplyCaller() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), |
| ReflectionFrames.class); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), |
| ReflectionFrames.class); |
| } |
| |
| @Test |
| public static void testHandleCaller() throws Exception { |
| // Sets the default walker which hides reflection |
| // frames. |
| StackInspector.walker.set(StackInspector.walkerHide); |
| |
| assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), |
| ReflectionFrames.class); |
| |
| // Sets a non-default walker configured to show |
| // reflection frames |
| StackInspector.walker.set(StackInspector.walkerShow); |
| |
| assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); |
| assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), |
| ReflectionFrames.class); |
| } |
| |
| static enum How { NEW, CONSTRUCTOR, CLASS}; |
| |
| /** |
| * An object that collect stack frames by walking the stack |
| * (and calling getCallerClass()) from within its constructor. |
| * For the purpose of this test, StackInspector objects are |
| * always created from the nested StackInspector.Caller class, |
| * which should therefore appear as the caller of the |
| * StackInspector constructor. |
| */ |
| static class StackInspector { |
| static final StackWalker walkerHide = |
| StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); |
| static final StackWalker walkerShow = |
| StackWalker.getInstance(EnumSet.of( |
| StackWalker.Option.RETAIN_CLASS_REFERENCE, |
| StackWalker.Option.SHOW_REFLECT_FRAMES)); |
| final static ThreadLocal<StackWalker> walker = new ThreadLocal<>() { |
| protected StackWalker initialValue() { |
| return walkerHide; |
| } |
| }; |
| |
| List<String> collectedFrames; |
| Class<?> cls = null; |
| boolean stop; |
| int filtered; |
| final boolean filterImplFrames; |
| |
| public StackInspector() { |
| stop = false; |
| // if reflection frames are not hidden, we want to |
| // filter implementation frames before collecting |
| // to avoid depending on internal details. |
| filterImplFrames = walker.get() == walkerShow; |
| collectedFrames = walker.get().walk(this::parse); |
| cls = walker.get().getCallerClass(); |
| } |
| |
| public List<String> collectedFrames() { |
| return collectedFrames; |
| } |
| |
| // The takeWhile method arrange for stopping frame collection |
| // as soon as a frame from ReflectionFrames.class is reached. |
| // The first such frame encountered is still included in the |
| // collected frames, but collection stops right after. |
| // This makes it possible to filter out anything above the |
| // the test method frame, such as frames from the test |
| // framework. |
| public boolean takeWhile(StackFrame f) { |
| if (stop) return false; |
| if (verbose) System.out.println(" " + f); |
| stop = stop || f.getDeclaringClass() == ReflectionFrames.class; |
| return true; |
| } |
| |
| // filter out implementation frames to avoid depending |
| // on implementation details. If present, Class::newInstance, |
| // Method::invoke and Constructor::newInstance will |
| // still appear in the collected frames, which is |
| // sufficient for the purpose of the test. |
| // In the case where the StackWalker itself is supposed to |
| // filter the reflection frames, then this filter will always |
| // return true. This way, if such a reflection frame appears when |
| // it sjould have been filtered by StackWalker, it will make the |
| // test fail. |
| public boolean filter(StackFrame f) { |
| if (filterImplFrames && |
| f.getClassName().startsWith("jdk.internal.reflect.")) { |
| filtered++; |
| return false; |
| } |
| if (!verbose) System.out.println(" " + f); |
| return true; |
| } |
| |
| public String frame(StackFrame f) { |
| return f.getClassName() + "::" + f.getMethodName(); |
| } |
| |
| List<String> parse(Stream<StackFrame> s) { |
| return s.takeWhile(this::takeWhile) |
| .filter(this::filter) |
| .map(this::frame) |
| .collect(Collectors.toList()); |
| } |
| |
| /** |
| * The Caller class is used to create instances of |
| * StackInspector, either direcltly, or throug reflection. |
| */ |
| public static class Caller { |
| public static StackInspector create(How how) throws Exception { |
| switch(how) { |
| case NEW: return new StackInspector(); |
| case CONSTRUCTOR: return StackInspector.class |
| .getConstructor().newInstance(); |
| case CLASS: return StackInspector.class.newInstance(); |
| default: throw new AssertionError(String.valueOf(how)); |
| } |
| } |
| public static StackInspector reflect(How how) throws Exception { |
| return (StackInspector) Caller.class.getMethod("create", How.class) |
| .invoke(null, how); |
| } |
| public static StackInspector handle(How how) throws Exception { |
| Lookup lookup = MethodHandles.lookup(); |
| MethodHandle mh = lookup.findStatic(Caller.class, "create", |
| MethodType.methodType(StackInspector.class, How.class)); |
| try { |
| return (StackInspector) mh.invoke(how); |
| } catch (Error | Exception x) { |
| throw x; |
| } catch(Throwable t) { |
| throw new AssertionError(t); |
| } |
| } |
| } |
| |
| public static Class<?> getCaller() throws Exception { |
| return walker.get().getCallerClass(); |
| } |
| |
| public static Class<?> reflectCaller() throws Exception { |
| return (Class<?>)StackWalker.class.getMethod("getCallerClass") |
| .invoke(walker.get()); |
| } |
| |
| public static Class<?> supplyCaller() throws Exception { |
| return ((Supplier<Class<?>>)StackInspector.walker.get()::getCallerClass).get(); |
| } |
| |
| public static Class<?> handleCaller() throws Exception { |
| Lookup lookup = MethodHandles.lookup(); |
| MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass", |
| MethodType.methodType(Class.class)); |
| try { |
| return (Class<?>) mh.invoke(walker.get()); |
| } catch (Error | Exception x) { |
| throw x; |
| } catch(Throwable t) { |
| throw new AssertionError(t); |
| } |
| } |
| } |
| } |