有没有办法通过调用堆栈内省找到被调用方法的签名。我们是否有任何替代方法可以找到相同的答案。我没有源代码,只有字节码文件
提前致谢。
堆栈自省将为您提供方法的调用者或最多提供方法的一些细节,对于精确的方法签名,您将不得不使用反射。
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
官方文档说:
返回表示此线程的堆栈转储的堆栈跟踪元素数组。如果此线程尚未启动或已终止,此方法将返回一个长度为零的数组。如果返回的数组长度非零,则数组的第一个元素表示堆栈的顶部,这是序列中最近的方法调用。数组的最后一个元素表示堆栈的底部,它是序列中最近的方法调用。
通过这种方式,您可以从StackTrace获取方法名称、文件名、行号。
对于完整的方法签名,您将不得不使用反射
您可以使用Java 反射和StackTraceElement。
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);
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(", "));
}
}