| /* |
| * 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().get(), fileName); |
| int line = f.getLineNumber().getAsInt(); |
| 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; |
| }); |
| } |
| } |
| } |