| /* | |
| * Copyright (c) 2015, 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 8143214 | |
| * @summary Verify StackWalker works well when embedded in another | |
| * StackWalker's functions. | |
| * @run testng/othervm EmbeddedStackWalkTest | |
| */ | |
| import java.lang.StackWalker.StackFrame; | |
| import static java.lang.StackWalker.Option.*; | |
| import java.lang.invoke.MethodHandle; | |
| import java.lang.invoke.MethodHandles; | |
| import java.lang.invoke.MethodType; | |
| import java.util.Arrays; | |
| import java.util.EnumSet; | |
| import org.testng.annotations.*; | |
| import static org.testng.Assert.*; | |
| public class EmbeddedStackWalkTest { | |
| static final StackWalker WALKERS[] = new StackWalker[] { | |
| StackWalker.getInstance(RETAIN_CLASS_REFERENCE), | |
| StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), | |
| StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) | |
| }; | |
| static final int BIG_LOOP = 30; | |
| static final int SMALL_LOOP = 5; | |
| @DataProvider | |
| public StackWalker[][] walkerProvider() { | |
| return new StackWalker[][] { | |
| new StackWalker[] { WALKERS[0] }, | |
| new StackWalker[] { WALKERS[1] }, | |
| new StackWalker[] { WALKERS[2] } | |
| }; | |
| } | |
| @Test(dataProvider = "walkerProvider") | |
| public void test(StackWalker walker) { | |
| C1.call(walker, BIG_LOOP); | |
| } | |
| // line numbers are hardcoded for now. | |
| // Should annotate the line numbers and auto-generated these constants | |
| // for test verification instead | |
| static final int BEGIN_LINE = 71; // the begin line number of approximate range. | |
| static final int END_LINE = 136; // the end line number of approximate range. | |
| static class C1 { // here is the begin line number of approximate range, L71. | |
| public static void call(StackWalker walker, int loops) { | |
| if (loops == 0) { | |
| String caller = walker.walk(s -> | |
| s.map(StackFrame::getClassName) | |
| .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) | |
| .skip(2).findFirst() | |
| ).get(); | |
| assertEquals(caller, C1.class.getName()); | |
| walker.forEach(f -> C2.testEmbeddedWalker()); | |
| } else { | |
| call(walker, --loops); | |
| } | |
| } | |
| } | |
| static class C2 { | |
| static final StackWalker embeddedWalkers[] = new StackWalker[] { | |
| StackWalker.getInstance(), | |
| StackWalker.getInstance(SHOW_REFLECT_FRAMES), | |
| StackWalker.getInstance(SHOW_HIDDEN_FRAMES) | |
| }; | |
| public static void testEmbeddedWalker() { | |
| walk(SMALL_LOOP); | |
| } | |
| static void walk(int loops) { | |
| if (loops == 0) { | |
| Arrays.stream(embeddedWalkers) | |
| .forEach(walker -> run(walker)); | |
| } else { | |
| walk(--loops); | |
| } | |
| } | |
| static void run(StackWalker walker) { | |
| MethodHandles.Lookup lookup = MethodHandles.lookup(); | |
| MethodHandle handle = null; | |
| try { | |
| handle = lookup.findStatic(C2.class, "call", | |
| MethodType.methodType(void.class, StackWalker.class)); | |
| handle.invoke(walker); | |
| } catch(Throwable t) { | |
| throw new RuntimeException(t); | |
| } | |
| } | |
| static void call(StackWalker walker) { | |
| String caller = walker.walk(s -> | |
| s.map(StackFrame::getClassName) | |
| .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) | |
| .skip(2).findFirst() | |
| ).get(); | |
| assertEquals(caller, C2.class.getName()); | |
| verify(walker, C1.class, "call"); | |
| verify(walker, C2.class, "call"); | |
| verify(walker, C2.class, "run"); | |
| verify(walker, C2.class, "walk"); | |
| verify(walker, C2.class, "testEmbeddedWalker"); | |
| } // here is the end line number of approximate range, L136. | |
| static void verify(StackWalker walker, Class<?> c, String mn) { | |
| final String fileName = "EmbeddedStackWalkTest.java"; | |
| walker.walk(s -> { | |
| s.limit(BIG_LOOP) | |
| .filter(f -> c.getName().equals(f.getClassName()) && mn.equals(f.getMethodName())) | |
| .forEach(f -> { | |
| assertEquals(f.getFileName(), fileName); | |
| int line = f.getLineNumber(); | |
| assertTrue(line >= BEGIN_LINE && line <= END_LINE); | |
| StackTraceElement st = f.toStackTraceElement(); | |
| assertEquals(c.getName(), st.getClassName()); | |
| assertEquals(mn, st.getMethodName()); | |
| assertEquals(st.getFileName(), fileName); | |
| line = st.getLineNumber(); | |
| assertTrue(line >= BEGIN_LINE && line <= END_LINE); | |
| }); | |
| return null; | |
| }); | |
| } | |
| } | |
| } |