Richard Hu
Richard Hu

Reputation: 891

How to get method signature (not method name) from Thread.currentThread().getStackTrace()?

Suppose I have the following methods and their invocations:

public static void main(String[] args) {zoo();}
public static void zoo() {zoo(0);}
public static void zoo(int i) {too(i);}
public static void too(int i) {...}

Thread.currentThread().getStackTrace() will return me with something like:

A.too(A.java:56)
A.zoo(A.java:65)
A.zoo(A.java:60)
A.main(A.java:80)

With this output, I cannot distinguish the 2 zoos I defined in my example, one without any parameter (zoo()) and one with an integer parameter (zoo(int i)). The reason is because only method names rather than their signatures are outputted. Is there a way to get a stack of method signatures?

Upvotes: 2

Views: 823

Answers (2)

Holger
Holger

Reputation: 298539

You can not get the method signature from a StackTraceElement, but since you’re interested in getting the stack trace of the currentThread, you can use StackWalker instead. Since Java 10, it supports getting the method type from a StackFrame.

For example

public class StackWalkerExample {
    public static void main(String[] args) {
        zoo();
        System.out.println();
        Arrays.asList("foo", "bar").sort((a, b) -> { getMethods(); return 0; });
    }

    public static void zoo() {zoo(0);}
    public static void zoo(int i) {too(i);}
    public static void too(int i) { getMethods(); }

    static void getMethods() {
        var sw = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
        var methods = sw.walk(frames ->
            frames.skip(1).map(StackWalkerExample::toMethod).toArray(Method[]::new));

        for(var m: methods) System.out.println(m);
    }

    static Method toMethod(StackWalker.StackFrame f) {
        try {
            return f.getDeclaringClass().getDeclaredMethod(
                    f.getMethodName(), f.getMethodType().parameterArray());
        } catch (NoSuchMethodException e) {
            throw new AssertionError(e);
        }
    }
}

will print

public static void StackWalkerExample.too(int)
public static void StackWalkerExample.zoo(int)
public static void StackWalkerExample.zoo()
public static void StackWalkerExample.main(java.lang.String[])

private static int StackWalkerExample.lambda$0(java.lang.String,java.lang.String)
private static int java.util.TimSort.countRunAndMakeAscending(java.lang.Object[],int,int,java.util.Comparator)
static void java.util.TimSort.sort(java.lang.Object[],int,int,java.util.Comparator,java.lang.Object[],int,int)
public static void java.util.Arrays.sort(java.lang.Object[],java.util.Comparator)
public void java.util.Arrays$ArrayList.sort(java.util.Comparator)
public static void StackWalkerExample.main(java.lang.String[])

Details of the sorting implementation may vary

Upvotes: 2

peterh
peterh

Reputation: 1

The documentation of the StackTraceElement in Java 13 clearly shows that there is no way to do that. You can identify the overloaded method by its line number with your human brain. Automatizing this task would be overkill if even possible (would require using hard reflection), although I do not close out that some lib can do that.

Remark: the binary file format of the .class files actually has the method signature information (at least the parameter list), thus it is not impossible, only no one developed it until now.

Upvotes: 2

Related Questions