Java 9부터는 java.lang.StackWalker 클래스를 통해 스택 프레임을 다루는 표준 API가 제공됩니다. 이 클래스는 스택 프레임에 대한 지연(lazy) 접근 방식을 허용하여 높은 효율성을 갖도록 설계되었습니다. 또한 구현(implementation) 프레임이나 리플렉션(reflection) 프레임까지 포함한 스택 트레이스를 얻을 수 있는 여러 옵션도 함께 제공되며, 이러한 기능은 디버깅 작업 시 특히 유용하게 활용됩니다.
예를 들어, StackWalker 인스턴스를 생성하는 시점에 SHOW_REFLECT_FRAMES 옵션을 지정하면 리플렉션 메서드에 해당하는 프레임들도 함께 출력할 수 있습니다.
아래 예제를 통해 StackFrame의 리플렉션 프레임을 표시하는 방법을 살펴보겠습니다.
예제
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
public class ReflectionFrameTest {
public static void main(String args[]) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method test1Method = Test1.class.getDeclaredMethod("test1", (Class[]) null);
test1Method.invoke(null, (Object[]) null);
}
}
class Test1 {
protected static void test1() {
Test2.test2();
}
}
class Test2 {
protected static void test2() {
// 리플렉션 메서드 표시
List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES).walk((s) -> s.collect(Collectors.toList()));
for(StackFrame frame : stack) {
System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
}
}
}실행 결과
Test2 22 test2 Test1 16 test1 jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0 jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke java.lang.reflect.Method 564 invoke ReflectionFrameTest 11 main
위 실행 결과를 보면, SHOW_REFLECT_FRAMES 옵션 덕분에 일반 애플리케이션 프레임(Test2, Test1, main)뿐만 아니라 jdk.internal.reflect 패키지와 java.lang.reflect.Method에 속한 내부 리플렉션 프레임들까지 모두 스택 트레이스에 포함되어 출력된 것을 확인할 수 있습니다. 이처럼 StackWalker를 활용하면 리플렉션 호출 경로를 명확하게 추적할 수 있어 문제 원인 분석에 큰 도움이 됩니다.