方法签名通过调用栈内省

时间:2012-06-08 08:02:15

标签: java

有没有办法通过调用堆栈内省找到被调用方法的签名。我们是否有任何替代方法可以找到相同的内容。我没有源代码,只有字节码文件

提前致谢。

3 个答案:

答案 0 :(得分:4)

堆栈内省将为您提供方法的调用者或最好的方法细节,对于精确的方法签名,您将不得不使用反射。

StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
  

官方文件说:

     

返回表示堆栈转储的堆栈跟踪元素数组   这个帖子。如果这样,此方法将返回零长度数组   线程尚未启动或已终止。如果返回的数组是   非零长度然后数组的第一个元素代表顶部   堆栈,这是最新的方法调用   序列。数组的最后一个元素代表了数组的底部   stack,这是序列中最近的方法调用。

StackTrace开始,您可以获取方法名称,文件名,亚麻。

要获得完整的方法签名,您必须使用反射

答案 1 :(得分:2)

您可以使用Java ReflectionStackTraceElement

StackTraceElement[] elements = new Throwable().getStackTrace();

    String calleeMethod = elements[0].getMethodName();
    String callerMethodName = elements[1].getMethodName();
    String callerClassName = elements[1].getClassName();

    System.out.println("CallerClassName=" + callerClassName + " , Caller method name: " + callerMethodName);
    System.out.println("Callee method name: " + calleeMethod);

答案 2 :(得分:0)

StackTraceElement不包含有关参数的任何信息,因此,如果调用类中有多个具有相同名称的方法,并且您想知道哪个方法,则需要访问源。对于原始问题,您可以尝试使用反编译器重新创建源,从这些源进行编译,然后重新创建堆栈跟踪并查看重新创建的源中的行号。

如果重载方法不是问题,您可以这样做:

public class TestTest {
    @Test
    public void overloaded1() throws Exception {
        doTheThing("foo", 42, this);
    }

    @Test
    public void overloaded2() throws Exception {
        doTheThing(1);
    }

    @Test
    public void notOverloaded() throws Exception {
        printMethodSignature();
    }

    public void doTheThing(int overloaded) throws Exception {
        printMethodSignature();
    }

    public void doTheThing(String dumm1, int dummy2, Object dummy3) throws Exception {
        printMethodSignature();
    }

    public void printMethodSignature() throws Exception {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        // elements[0] will contain java.lang.Thread.getStackTrace() here
        // elements[1] will contain this method: printMethodSignature()
        // elements[2] will contain the method from which printMethodSignature() was called

        System.out.println(elements[2] + " -> " + toSignature(elements[2]));
    }

    // Represent class & method as string
    public String toSignature(StackTraceElement st) throws Exception {
        Class callingClass = Class.forName(st.getClassName());
        return Stream.of(callingClass.getMethods())
            .filter(m -> m.getName().equals(st.getMethodName()))
            .map(m -> String.format("%s.%s(%s)", callingClass.getName(), m.getName(), toSignature(m)))
            .collect(Collectors.joining("\n"));
    }

    // Represent parameters as a String
    public String toSignature(Method method) {
        return Stream.of(method.getParameters())
            .map(p -> p.getParameterizedType().getTypeName())
            .collect(Collectors.joining(", "));
    }
}