StackWalker.getCallerClass() returns the caller's Class. Formerly we had to use Throwable.getStackTrace() or Thread.getStackTrace() methods to do the same, there we had to loop through and drop unwanted frames to find the immediate caller. JDK itself has internally been using these methods or sun.reflect.Reflection#getCallerClass() (which forwards call to a native method) to find the immediate caller in different cases. Reflection#getCallerClass() has been deprecated in Java 9 and will be removed in a future release.
Example
Using StackWalker.getCallerClass()
public class StackWalkerCallerExample1 {
public static void main(String[] args) {
TheCallerClass sc = new TheCallerClass();
sc.doSomething();
}
public static final class TheCallerClass {
public void doSomething() {
TheCalleeClass theCalleeClass = new TheCalleeClass();
theCalleeClass.work();
}
}
public static final class TheCalleeClass {
public void work() {
StackWalker instance = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Class<?> callerClass = instance.getCallerClass();
System.out.println(callerClass);
}
}
}
In above example we used StackWalker.Option.RETAIN_CLASS_REFERENCE option which is needed when we use StackWalker.getCallerClass() method (we also used it in our last example while using StackFrame.getDeclaringClass() .
Outputclass com.logicbig.example.StackWalkerCallerExample1$TheCallerClass
In our above example, the StackWalker.getCallerClass() method is equivalent to the following StackWalker.walk() usage:
....
public static final class TheCalleeClass {
public void work() {
StackWalker instance = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Optional<? extends Class<?>> opt = instance.walk(
stream -> stream.map(StackFrame::getDeclaringClass)
.skip(1)
.findFirst());
if (opt.isPresent()) {
Class<?> aClass = opt.get();
System.out.println(aClass);
}
}
}
.....
Let's use the old way of looping though StackTraceElements :
public class StackWalkerCallerExample2 {
public static void main(String[] args) {
TheCallerClass sc = new TheCallerClass();
sc.doSomething();
}
public static final class TheCallerClass {
public void doSomething() {
TheCalleeClass theCalleeClass = new TheCalleeClass();
theCalleeClass.work();
}
}
public static final class TheCalleeClass {
public void work() {
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste.getClassName());
}
}
}
} Outputjava.lang.Thread com.logicbig.example.StackWalkerCallerExample2$TheCalleeClass com.logicbig.example.StackWalkerCallerExample2$TheCallerClass com.logicbig.example.StackWalkerCallerExample2
As seen in above output, our required caller class is in the third stack frame.
Using Reflection
When using Java reflection, StackWalker.getCallerClass() filters reflection stack traces, whereas the old way of using StackTraceElements shows all internal reflection calls. This includes the cases when using the methods such as Method.invoke() or Constructor.newInstance() or recently deprecated method Class.newInstance(). Let's see an example.
public class StackWalkerCallerExample3 {
public static void main(String[] args) {
TheCallerClass sc = new TheCallerClass();
sc.doSomethingReflectively();
}
public static class TheCallerClass {
public void doSomethingReflectively() {
try {
TheCalleeClass theCallerClass = TheCalleeClass.class
.getConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static class TheCalleeClass {
public TheCalleeClass() {
System.out.println("-- using StackWalker --");
StackWalker instance = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Class<?> callerClass = instance.getCallerClass();
System.out.println(callerClass);
System.out.println("-- using stack trace --");
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste.getClassName());
}
}
}
} Output-- using StackWalker -- class com.logicbig.example.StackWalkerCallerExample3$TheCallerClass -- using stack trace -- java.lang.Thread com.logicbig.example.StackWalkerCallerExample3$TheCalleeClass jdk.internal.reflect.NativeConstructorAccessorImpl jdk.internal.reflect.NativeConstructorAccessorImpl jdk.internal.reflect.DelegatingConstructorAccessorImpl java.lang.reflect.Constructor com.logicbig.example.StackWalkerCallerExample3$TheCallerClass com.logicbig.example.StackWalkerCallerExample3
Example ProjectDependencies and Technologies Used: |