SHOW_HIDDEN_FRAMES

Finally, the enum constant option, SHOW_HIDDEN_FRAMES will include all the hidden frames, which contain reflective calls as well as call frames that are generated for Lambda function calls.

Here is a simple demonstration of reflective and hidden frames:

package packt;
import static java.lang.StackWalker.Option.SHOW_HIDDEN_FRAMES;
import static java.lang.StackWalker.Option.SHOW_REFLECT_FRAMES;
public class Main {

The main method allowing us to execute this code directly calls the simpleCall() method:

public static void main(String[] args) {
simpleCall();
}

The simpleCall() method simply calls on, as the name suggests:

static void simpleCall() {
reflectCall();
}

The next method in the chain is a bit more complex. Although this also only calls the next one, it does so using reflection:

static void reflectCall() {
try {
Main.class.getDeclaredMethod("lambdaCall",
new Class[0]).invoke(null, new Object[0]);
} catch (Exception e) {
throw new RuntimeException();
}
}

In this next example, we have a method that calls using a Lambda:

static void lambdaCall() {
Runnable r = () -> {
walk();
};
r.run();
}

The last method before the actual walking is called walk():

static void walk() {
noOptions();
System.out.println();
reflect();
System.out.println();
hidden();
}

The preceding walk() method calls three methods, one after the other. These methods are very similar to each other and are shown here:

static void noOptions() {
StackWalker
.getInstance()
.forEach(System.out::println);
}

static void reflect() {
StackWalker
.getInstance(SHOW_REFLECT_FRAMES)
.forEach(System.out::println);
}

static void hidden() {
StackWalker
.getInstance(SHOW_HIDDEN_FRAMES)
.forEach(System.out::println);
}

The preceding three methods print out the frames to the standard output. They use the forEach() method of StackWalker. Here is the output of the stack walking program:

stackwalker/packt.Main.noOptions(Main.java:45)
stackwalker/packt.Main.walk(Main.java:34)
stackwalker/packt.Main.lambda$lambdaCall$0(Main.java:28)
stackwalker/packt.Main.lambdaCall(Main.java:30)
stackwalker/packt.Main.reflectCall(Main.java:19)
stackwalker/packt.Main.simpleCall(Main.java:12)
stackwalker/packt.Main.main(Main.java:8)

This output only contains the frames that belong to calls that are in our code. The main() method calls simpleCall(), which calls reflectCall(), that in turn calls lambdaCall(), which calls a Lambda expression, which calls walk(), and so on. The fact that we did not specify any option does not delete the Lambda call from the stack. We performed that call, thus it must be there. What it deletes are the extra stack frames that are needed by the JVM to implement the Lambda. We can see in the next output, when the option was SHOW_REFLECT_FRAMES, that the reflective frames are already there:

stackwalker/packt.Main.reflect(Main.java:58)
stackwalker/packt.Main.walk(Main.java:36)
stackwalker/packt.Main.lambda$lambdaCall$0(Main.java:28)
stackwalker/packt.Main.lambdaCall(Main.java:30)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:547)
stackwalker/packt.Main.reflectCall(Main.java:19)
stackwalker/packt.Main.simpleCall(Main.java:12)
stackwalker/packt.Main.main(Main.java:8)

In this case, the difference is that we can see that the call from the reflectCall() method to the lambdaCall() method is not direct. The reflectCall() method calls the invoke() method that calls another method of the same name defined in a different class that in turn calls the invoke() method, which is a native method provided by the JVM. After that, we finally get to the lambdaCall() method.

In the output, we can also see that these reflective calls belong to the java.base module and not our StackWalker module.

If we include the hidden frames in addition to the reflective frames, specifying the option SHOW_HIDDEN_FRAMES, then we will see the following output:

stackwalker/packt.Main.hidden(Main.java:52)
stackwalker/packt.Main.walk(Main.java:38)
stackwalker/packt.Main.lambda$lambdaCall$0(Main.java:28)
stackwalker/packt.Main$$Lambda$46/269468037.run(Unknown Source)
stackwalker/packt.Main.lambdaCall(Main.java:30)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:547)
stackwalker/packt.Main.reflectCall(Main.java:19)
stackwalker/packt.Main.simpleCall(Main.java:12)
stackwalker/packt.Main.main(Main.java:8)

This includes an extra hidden frame that the JVM is using to execute the Lambda call. In addition, the reflective frames are also included.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset