Introduction to StackWalker API In Java 9
In this post, we will be covering StackWalker API in Java 9. Stack Walking API is yet another features being introduced in Java 9
Introduction
To put Stack Walk API in Java 9 in simple words, It provides capabilities to walk through the stack in Java. StackWalker provides a snapshot of the current thread stack trace along with some methods to access it.
Before Java 9, There was no standard / efficient way to access selected frames of the stack and get information about the Class instance of each frame. We have the following options available to get information from the Stack Trace
getStackTrace()
method fromjava.lang.Throwable
Class which returns an array ofStackTraceElement.
So if you want to get information about the stack trace before Java 9, a simpler code will look similar to
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
Above method require JVM to capture the snapshot of the entire stack and return this information back to the calling method / API. This is not a very efficient solution due to following use cases.
- Capturing the entire snapshot of the stack is not an efficient memory operation and will have an impact.
- You might only need some frame from the stack but still, you will be provided with the entire snapshot.
- Taking into account the second point, We have to process some frames which might not be useful for us.
- One of the most important points is that as part of StackTraceElement objects, you will get information about the class name, method name but will never get hold of the actual
Class
instance. - Some of the VM implementation may strip some stack information in favor of performance, so you might not get full stack information even when calling
Thread.getStackTrace()
method.
If you want you can use java.lang.SecurityManager.getClassContext()
method to get access to the Class instance but I will not be covering that part in this post.
1. Why Use StackWalker
One of natural question which comes to our mind is why do we need StackWalker API in Java 9? Here are some of the benefits which you will be getting from this new API.
- It will provide you a way to filter/skip classes which give us the flexibility to process our interest specific classes.
- StackWalker API provides a way to load only certain frames (e.g. load only 10 frames) which will be helping us to handle performance issue.
- We can directly get instance of the declaring class without using
java.lang.SecurityManager.getClassContext()
method. - It will provide you a way to understanding application behavior more easily.
2. StackWalker Basic
Let’s cover some of the basic of the StackWalker API along with details as to how we can use it in future.StackWalker class is easy to use and provide some convenient method to work on the stack.
2.1 Obtaining a StackWalker
StackWalker API provides a static getInstance method which can be used to obtained StackWalker instance.
StackWalker stackWalker = StackWalker.getInstance();
There are other variants of the getInstance()
method which can be used based on the individual requirements.
Let’s start building our example to demonstrate various features of the StackWalker API in Java 9.
3 StackWalker Demo
Here is our sample class with some method creating method chain.
package com.umeshawasthi.java9.example.stackwalker;
public class StackWalkerExample {
public static void stackWalkerMethod1() {
stackWalkerMethod1();
}
public static void stackWalkerMethod2() {
stackWalkerMethod2();
}
public static void stackWalkerMethod3() {
stackWalkerMethod3();
}
public static void stackWalkerMethod4() {
mainWalkerMethod();
}
public static void printCompleteStackTrace() {
}
}
3.1 Get All Stack Information
In order to get the complete stack, we will get an instance of the StackWalker and will use walk method to opens a sequential stream.
public static void printCompleteStackTrace() {
List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk((s) -> s.collect(Collectors.toList()));
stack.forEach(System.out::println);
}
In above method we get an instance of the StackWalker and use the walk method opens a sequential stream of StackFrames for the current thread.
Here is the output of the above method.
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.printCompleteStackTrace(StackWalkerExample.java:39)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod3(StackWalkerExample.java:28)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod2(StackWalkerExample.java:23)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.stackWalkerMethod1(StackWalkerExample.java:18)
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerExample.main(StackWalkerExample.java:13)
3.2 Filter StackFrames for Certain Classes
Let’s say we are only interested in a stack from a specific class, to achieve this we do not have to go through each and every frame. StackWalker API provides a convenient option to filter out results which are of our interest.
public void filterStackFrame() {
List<StackWalker.StackFrame> filterFrames = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk((s) -> s.filter(f -> f.getClassName().contains(StackWalkerDemo3.class.getName()))
.collect(Collectors.toList()));
filterFrames.forEach(System.out::println);
}
As we saw in above example, We are only interested in the StackFrame from the StackWalkerDemo3 class, so we passed it as a filter and StackWalker API will filter out it for us. Below is the output of the above code
java/com.umeshawasthi.java9.example.stackwalker.StackWalkerFilterExample$StackWalkerDemo3.stackWalkerMethod3(StackWalkerFilterExample.java:35)
3.3 Shows all Reflection and Hidden Frames
StackWalker API provides a way to show all reflection and hidden Frames which are hidden by default. StackWalker configured with this SHOW_REFLECT_FRAMES option will show all reflection frames, a similar way we can use SHOW_HIDDEN_FRAMES to show all hidden frames.
public static void printCompleteStackTrace() {
List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.SHOW_REFLECT_FRAMES)
.walk((s) -> s.collect(Collectors.toList()));
stack.forEach(System.out::println);
}
3.4 Limit Number of StackFrames
Let’s say we just want the top 3 stack frames from the current thread, we can use limit option for achieving this.
List<StackWalker.StackFrame> stack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk((s) ->s.limit(3).collect(Collectors.toList()));
3.5 Get Calling Class Instance
We discussed in the starting of this post that StackWalker API provides a way to get hold of the calling class Instance which was not possible before Java 9 (We do have some indirect way). To get hold of the calling class instance you need RETAIN_CLASS_REFERENCE
while getting StackWalker instance.
RETAIN_CLASS_REFERENCE
will retain an instance of all classes walked by StackWalker, we can use getCallerClass and getDeclaringClass method to get hold of the class instance.
public static void getCallerClass() {
Class calledClass = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.getCallerClass();
System.out.println("Caller Class is " +calledClass.getCanonicalName());
}
Output of above program is
Caller Class is com.umeshawasthi.java9.example.stackwalker.StackWalkerGetClass
4 Summary
In this post, we explore StackWalker API being introduced in Java 9. We checked how we can get stack based on our requirement with an option to filter or limit results along with the ability to display hidden frames. We explored possibility to get hold of the calling Class instance using Java 9 StackWalker API
If you are interested in learning other features being introduced in Java 9, Please read following posts on Java 9
Collection Factory Methods in Java 9
All the code of this article is available Over on Github. This is a Maven-based project.
References
Comments are closed.