下面列出了怎么用java.lang.StackWalker.StackFrame的API类实例代码及写法,或者点击链接到github查看源代码。
@Nonnull
@Override
public Observable<ResponsePayload> queue(@Nonnull final OutboundRequest r) {
final CompletableFuture<ResponsePayload> future = new CompletableFuture<>();
final Bucket bucket = getBucket(r.route());
// Capture stacktrace if possible
final StackTraceElement[] stacktrace;
if(catnip.options().captureRestStacktraces()) {
stacktrace = STACK_WALKER.walk(stream -> stream
.map(StackFrame::toStackTraceElement)
.toArray(StackTraceElement[]::new));
} else {
stacktrace = new StackTraceElement[0];
}
bucket.queueRequest(new QueuedRequest(r, r.route(), future, bucket, stacktrace));
return RxHelpers.futureToObservable(future)
.subscribeOn(catnip.rxScheduler())
.observeOn(catnip.rxScheduler());
}
@Override
public boolean tryAdvance(Consumer<? super StackFrame> action) {
checkState(OPEN);
int index = frameBuffer.getIndex();
if (hasNext()) {
StackFrame frame = nextStackFrame();
action.accept(frame);
if (isDebug) {
System.err.println("tryAdvance: " + index + " " + frame);
}
return true;
}
if (isDebug) {
System.err.println("tryAdvance: " + index + " NO element");
}
return false;
}
/**
* Returns true if we have found the caller's frame, false if the frame
* must be skipped.
*
* @param t The frame info.
* @return true if we have found the caller's frame, false if the frame
* must be skipped.
*/
@Override
public boolean test(StackWalker.StackFrame t) {
final String cname = t.getClassName();
// We should skip all frames until we have found the logger,
// because these frames could be frames introduced by e.g. custom
// sub classes of Handler.
if (lookingForLogger) {
// Skip all frames until we have found the first logger frame.
lookingForLogger = !isLoggerImplFrame(cname);
return false;
}
// Continue walking until we've found the relevant calling frame.
// Skips logging/logger infrastructure.
return !Formatting.isFilteredFrame(t);
}
@Override
public boolean tryAdvance(Consumer<? super StackFrame> action) {
checkState(OPEN);
int index = frameBuffer.getIndex();
if (hasNext()) {
StackFrame frame = nextStackFrame();
action.accept(frame);
if (isDebug) {
System.err.println("tryAdvance: " + index + " " + frame);
}
return true;
}
if (isDebug) {
System.err.println("tryAdvance: " + index + " NO element");
}
return false;
}
/**
* Returns true if we have found the caller's frame, false if the frame
* must be skipped.
*
* @param t The frame info.
* @return true if we have found the caller's frame, false if the frame
* must be skipped.
*/
@Override
public boolean test(StackWalker.StackFrame t) {
final String cname = t.getClassName();
// We should skip all frames until we have found the logger,
// because these frames could be frames introduced by e.g. custom
// sub classes of Handler.
if (lookingForLogger) {
// Skip all frames until we have found the first logger frame.
lookingForLogger = !isLoggerImplFrame(cname);
return false;
}
// Continue walking until we've found the relevant calling frame.
// Skips logging/logger infrastructure.
return !Formatting.isFilteredFrame(t);
}
/**
* Perform stackwalk, keeping local variables alive, and return a list of
* the collected StackFrames
*/
private synchronized StackFrame[] testLocalsKeepAlive() {
int x = 0xA;
char c = 'z'; // 0x7A
String hi = "himom";
long l = 0x3FF00000000L + 0xFFFFL;
double d = Math.PI;
StackFrame[] frames = walker.walk(s ->
s.filter(f -> TEST_METHODS.contains(f.getMethodName()))
.toArray(StackFrame[]::new)
);
// Use local variables so they stay alive
System.out.println("Stayin' alive: "+this+" "+x+" "+c+" "+hi+" "+l+" "+d);
return frames;
}
private static void usedLong(long longArg) throws Exception {
StackFrame[] frames = extendedWalker.walk(s ->
s.filter(f -> "usedLong".equals(f.getMethodName()))
.toArray(StackFrame[]::new)
);
try {
dumpFramesIfDebug(frames);
Object[] locals = (Object[]) getLocals.invoke(frames[0]);
assertLongIsInSlots(locals[0], locals[1], longArg);
System.out.println("Stayin' alive: " + longArg);
} catch (Exception t) {
dumpFramesIfNotDebug(frames);
throw t;
}
}
private static void usedDouble(double doubleArg) throws Exception {
StackFrame[] frames = extendedWalker.walk(s ->
s.filter(f -> "usedDouble".equals(f.getMethodName()))
.toArray(StackFrame[]::new)
);
try {
dumpFramesIfDebug(frames);
Object[] locals = (Object[]) getLocals.invoke(frames[0]);
assertDoubleIsInSlots(locals[0], locals[1], doubleArg);
System.out.println("Stayin' alive: " + doubleArg);
} catch (Exception t) {
dumpFramesIfNotDebug(frames);
throw t;
}
}
public boolean accept(StackFrame f) {
// Frames whose class names don't contain "."
// are our own test frames. These are the ones
// we expect.
// Frames whose class names contain ".reflect."
// are reflection frames. None should be present,
// since they are supposed to be filtered by
// by StackWalker. If we find any, we want to fail.
if (!f.getClassName().contains(".")
|| f.getClassName().contains(".reflect.")) {
System.out.println(" " + f);
return true;
}
// Filter out all other frames (in particular
// those from the test framework) in order to
// have predictable results.
return false;
}
public void consume(StackFrame sf) {
if (count == 0 && swOptions.contains(StackWalker.Option.RETAIN_CLASS_REFERENCE)
&& isStreamPipeline(sf.getDeclaringClass())) {
return;
}
if (verbose) {
System.out.println("\t" + sf.getClassName() + "." + sf.getMethodName());
}
if (count >= recorder.frameCount()) {
// We've gone past main()...
if (infrastructureClasses.contains(sf.getClassName())) {
// safe to ignore
return;
}
}
try {
recorder.compareFrame(count, sf);
} catch (IndexOutOfBoundsException e) {
// Extra non-infra frame in stream
throw new RuntimeException("extra non-infra stack frame at count "
+ count + ": <" + sf + ">", e);
}
count++;
}
static void firstFrame() {
System.out.println("first frame()");
StackWalker sw = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
sw.forEach(e -> {
System.out.println(e.getClassName() + "," + e.getMethodName());
});
System.out.println("\n");
Optional<StackFrame> frame = sw.walk(s ->
{
return s.filter(e -> {
System.err.println(e.getClassName() + " == " +
e.getClassName().equals("StackStreamTest"));
return e.getClassName().equals("StackStreamTest");
}).findFirst();
});
Class<?> c = frame.get().getDeclaringClass();
System.out.println("\nfirst frame: " + c);
if (c != StackStreamTest.class) {
throw new RuntimeException("Unexpected first caller class " + c);
}
}
/**
* {@inheritDoc}
* <p>This method inspects the stack trace and checks who is calling
* {@link System#exit(int)} and similar methods
* @throws SecurityException if the caller of this method is not the test runner itself.
*/
@Override
public void checkExit(final int status) {
if (StackWalker.getInstance().walk(s -> s
.dropWhile(Predicate.not(TestSecurityManager::isExitStackFrame)) // skip all internal stack frames
.dropWhile(TestSecurityManager::isExitStackFrame) // skip all exit()/halt() stack frames
.limit(1) // only look at one more frame (caller of exit)
.map(StackFrame::getClassName)
.noneMatch(c -> c.startsWith(JUNIT4_TEST_RUNNER_PACKAGE) ||
c.startsWith(ECLIPSE_TEST_RUNNER_PACKAGE) ||
c.startsWith(IDEA_TEST_RUNNER_PACKAGE) ||
c.startsWith(GRADLE_TEST_RUNNER_PACKAGE)))) {
throw new SecurityException(String.format(Locale.ENGLISH,
"System/Runtime.exit(%1$d) or halt(%1$d) calls are not allowed because they terminate the test runner's JVM.",
status));
}
// we passed the stack check, delegate to super, so default policy can still deny permission:
super.checkExit(status);
}
/**
* Returns true if we have found the caller's frame, false if the frame
* must be skipped.
*
* @param t The frame info.
* @return true if we have found the caller's frame, false if the frame
* must be skipped.
*/
@Override
public boolean test(StackWalker.StackFrame s) {
// We should skip all frames until we have found the logger,
// because these frames could be frames introduced by e.g. custom
// sub classes of Handler.
Class<?> c = s.getDeclaringClass();
boolean isLogger = System.Logger.class.isAssignableFrom(c);
if (lookingForLogger) {
// Skip all frames until we have found the first logger frame.
lookingForLogger = c != TestLogger.class;
return false;
}
// Continue walking until we've found the relevant calling frame.
// Skips logging/logger infrastructure.
return !isLogger;
}
static <T> StackFrameTraverser<T>
makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
{
if (walker.hasLocalsOperandsOption())
return new LiveStackInfoTraverser<>(walker, function);
else
return new StackFrameTraverser<>(walker, function);
}
@Nullable
public StackTraceElement getCallerPlace(Predicate<String> locationAwareClassChecker, Predicate<String> ignore) {
return stackWalker.walk(new Function<>() {
private boolean afterSelf = false;
private boolean afterDeprecated = false;
private Class<?> deprecatedClass = null;
@Override
public StackTraceElement apply(Stream<StackFrame> stream) {
return stream
.filter(stack -> {
if (isReflection(stack.getClassName())) {
return false;
}
Class<?> declaringClass = stack.getDeclaringClass();
if (locationAwareClassChecker.test(declaringClass.getName())) {
afterSelf = true;
return false;
}
if (afterSelf) {
if (deprecatedClass == null) {
deprecatedClass = declaringClass;
}
}
if (declaringClass == deprecatedClass) {
afterDeprecated = true;
return false;
}
if (ignore.test(declaringClass.getName())) {
return false;
}
return afterDeprecated;
})
.findAny()
.map(StackFrame::toStackTraceElement)
.orElse(null);
}
});
}
@Override
public void forEachRemaining(Consumer<? super StackFrame> action) {
checkState(OPEN);
for (int n = 0; n < maxDepth; n++) {
StackFrame frame = nextStackFrame();
if (frame == null) break;
action.accept(frame);
}
}
private String getCallerInfo() {
Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
if (frame.isPresent()) {
return frame.get().getClassName() + " " + frame.get().getMethodName();
} else {
return name;
}
}
static boolean isFilteredFrame(StackFrame st) {
// skip logging/logger infrastructure
if (System.Logger.class.isAssignableFrom(st.getDeclaringClass())) {
return true;
}
// fast escape path: all the prefixes below start with 's' or 'j' and
// have more than 12 characters.
final String cname = st.getClassName();
char c = cname.length() < 12 ? 0 : cname.charAt(0);
if (c == 's') {
// skip internal machinery classes
if (cname.startsWith("sun.util.logging.")) return true;
if (cname.startsWith("sun.rmi.runtime.Log")) return true;
} else if (c == 'j') {
// Message delayed at Bootstrap: no need to go further up.
if (cname.startsWith("jdk.internal.logger.BootstrapLogger$LogEvent")) return false;
// skip public machinery classes
if (cname.startsWith("jdk.internal.logger.")) return true;
if (cname.startsWith("java.util.logging.")) return true;
if (cname.startsWith("java.lang.invoke.MethodHandle")) return true;
if (cname.startsWith("java.security.AccessController")) return true;
}
// check additional prefixes if any are specified.
if (skips.length > 0) {
for (int i=0; i<skips.length; i++) {
if (!skips[i].isEmpty() && cname.startsWith(skips[i])) {
return true;
}
}
}
return false;
}
public long longArg(int i, long l) throws Throwable {
List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit
long locals_2 = (long) longValue.invoke(locals[2]);
if (locals_2 != 0){
throw new RuntimeException("Expected locals_2 == 0");
}
}
return l; // Don't want l to become a dead var
}
/** Returns true if the loader that loaded the frame's declaring class
* is a user loader (if it is not the platform class loader or one of
* its ancestor).
*/
private boolean isUserLoader(StackFrame sf) {
ClassLoader cl = sf.getDeclaringClass().getClassLoader();
if (cl == null) return false;
ClassLoader p = ClassLoader.getPlatformClassLoader();
while (cl != p && p != null) p = p.getParent();
return cl != p;
}
static <T> StackFrameTraverser<T>
makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
{
if (walker.hasLocalsOperandsOption())
return new LiveStackInfoTraverser<>(walker, function);
else
return new StackFrameTraverser<>(walker, function);
}
/**
* Returns next StackFrame object in the current batch of stack frames;
* or null if no more stack frame.
*/
StackFrame nextStackFrame() {
if (!hasNext()) {
return null;
}
StackFrameInfo frame = frameBuffer.nextStackFrame();
depth++;
return frame;
}
public String walkExample3(Stream<StackFrame> stackFrameStream) {
return stackFrameStream.filter(frame -> frame.getClassName()
.contains("com.baeldung")
&& frame.getClassName()
.endsWith("Test"))
.findFirst()
.map(frame -> frame.getClassName() + "#" + frame.getMethodName() + ", Line " + frame.getLineNumber())
.orElse("Unknown caller");
}
private String getCallerInfo() {
Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
if (frame.isPresent()) {
return frame.get().getClassName() + " " + frame.get().getMethodName();
} else {
return name;
}
}
static boolean isFilteredFrame(StackFrame st) {
// skip logging/logger infrastructure
if (System.Logger.class.isAssignableFrom(st.getDeclaringClass())) {
return true;
}
// fast escape path: all the prefixes below start with 's' or 'j' and
// have more than 12 characters.
final String cname = st.getClassName();
char c = cname.length() < 12 ? 0 : cname.charAt(0);
if (c == 's') {
// skip internal machinery classes
if (cname.startsWith("sun.util.logging.")) return true;
if (cname.startsWith("sun.rmi.runtime.Log")) return true;
} else if (c == 'j') {
// Message delayed at Bootstrap: no need to go further up.
if (cname.startsWith("jdk.internal.logger.BootstrapLogger$LogEvent")) return false;
// skip public machinery classes
if (cname.startsWith("jdk.internal.logger.")) return true;
if (cname.startsWith("java.util.logging.")) return true;
if (cname.startsWith("java.lang.invoke.MethodHandle")) return true;
if (cname.startsWith("java.security.AccessController")) return true;
}
// check additional prefixes if any are specified.
if (skips.length > 0) {
for (int i=0; i<skips.length; i++) {
if (!skips[i].isEmpty() && cname.startsWith(skips[i])) {
return true;
}
}
}
return false;
}
public void recordSTE(long counter, StringBuilder s, StackFrame f) {
if (found) return;
found = VerifyStackTrace.class.equals(f.getDeclaringClass()) &&
"main".equals(f.getMethodName());
String line = String.format("%d: %s", counter, f.toStackTraceElement());
s.append(line).append('\n');
System.out.println(line);
}
private static String newWalk(Stream<StackFrame> stackFrameStream) {
return stackFrameStream
.filter(frame -> frame.getMethodName().contains("one"))
.findFirst()
.map(frame -> "Line " + frame.getLineNumber())
.orElse("Unknown line");
}
/** Calls KnownLocalsTester.testLocals* and provides LiveStackFrames */
@DataProvider
public static StackFrame[][] knownLocalsProvider() {
List<StackFrame[]> list = new ArrayList<>(3);
list.add(new KnownLocalsTester().testLocalsKeepAlive());
list.add(new KnownLocalsTester().testLocalsKeepAliveArgs(0xA, 'z',
"himom", 0x3FF00000000L + 0xFFFF, Math.PI));
if (testUnused) {
list.add(new KnownLocalsTester().testLocalsUnused());
}
return list.toArray(new StackFrame[1][1]);
}
/**
* Check for expected local values in the LiveStackFrame
*/
@Test(dataProvider = "knownLocalsProvider")
public static void checkLocalValues(StackFrame... frames) {
dumpFramesIfDebug(frames);
try {
Stream.of(frames)
.filter(f -> KnownLocalsTester.TEST_METHODS.contains(f.getMethodName()))
.forEach(LocalsAndOperands::checkFrameLocals);
} catch (Exception e) { dumpFramesIfNotDebug(frames); throw e; }
}
/**
* Check the locals in the given StackFrame against the expected values.
*/
private static void checkFrameLocals(StackFrame f) {
Object[] expectedArray = KnownLocalsTester.LOCAL_VALUES;
Object[] locals = invokeGetLocals(f);
for (int i = 0; i < locals.length; i++) {
Object expected = expectedArray[i];
Object observed = locals[i];
if (expected == null) { /* skip nulls in golden values */
continue;
} else if (expected instanceof KnownLocalsTester.TwoSlotValue) {
// confirm integrity of expected values
assertEquals(expectedArray[i+1], null,
"Malformed array of expected values - slot after TwoSlotValue should be null");
assertLongIsInSlots(locals[i], locals[i+1],
((KnownLocalsTester.TwoSlotValue)expected).value);
i++; // skip following slot
} else if (primitiveSlotClass.isInstance(observed)) { // single slot primitive
assertTrue(primitiveValueEquals(observed, expected),
"Local value mismatch: local " + i + " value is " +
observed + ", expected " + expected);
} else if (expected instanceof Class) {
assertTrue(((Class)expected).isInstance(observed),
"Local value mismatch: local " + i + " expected instancof " +
expected + " but got " + observed);
} else if (expected instanceof String) {
assertEquals(expected, observed, "Local value mismatch: local " +
i + " value is " + observed + ", expected " + expected);
} else {
throw new RuntimeException("Unrecognized expected local value " +
i + ": " + expected);
}
}
}