使用反射或其他方法获取方法的行号是否可能?
如果该方法位于当前堆栈跟踪中,则可以使用Thread.currentThread().getStackTrace()
获取StackTraceElement
的行号。但是如果我只有java.lang.reflect.Method
对象怎么办?
我找到了这个关于类的内容-> 如何从java.lang.Class对象获取源文件名/行号, 但对于方法来说并不实用。
使用反射或其他方法获取方法的行号是否可能?
如果该方法位于当前堆栈跟踪中,则可以使用Thread.currentThread().getStackTrace()
获取StackTraceElement
的行号。但是如果我只有java.lang.reflect.Method
对象怎么办?
我找到了这个关于类的内容-> 如何从java.lang.Class对象获取源文件名/行号, 但对于方法来说并不实用。
我希望做同样的事情,在一些研究后选择了javassist。您需要添加javassist库(我使用的是版本3.15.0-GA)。
给定以下类,确定“x”方法的位置。“x”方法名称是硬编码的,但是如果您和我一样,反射并不难,因此我有信心您可以获取方法名称列表,然后以下内容将让您获取方法的行号:
public class Widget {
void x(){System.out.println("I'm x\n");}
//comment added to create space
void y(){System.out.println("I'm y\n");}
}
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public class App {
public static void main(String[] args) throws NotFoundException {
System.out.println("Get method line number with javassist\n");
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.quaternion.demo.Widget");
CtMethod methodX = cc.getDeclaredMethod("x");
int xlineNumber = methodX.getMethodInfo().getLineNumber(0);
System.out.println("method x is on line " + xlineNumber + "\n");
}
}
输出: 方法x在第12行
,在我的情况下这是精确的。我删掉了一些注释...
注: 如Pete83在评论中提到的那样,这个方法实际上返回的是该方法中的第一行代码而不是声明该方法的行。这通常不会成为问题,因为大多数人可能想要建立相对位置(它们被声明的顺序)并使用此信息进行自己的约定。每当您感到有必要在注释中包含序数值时,并且可以通过代码本身的位置轻松确定该值,就会出现这种情况。
<dependency>
<groupId>org.javassist</groupId> <!-- if a version prior to 3.13.0-GA is needed use "javassist" and not "org.javassist" -->
<artifactId>javassist</artifactId>
<version>3.15.0-GA</version>
</dependency>
对我来说,Quaternion指向Javassist的答案是这个问题的完美解决方案。它对我起作用,当你只获得java.lang.reflect.Method对象时,你也可以使用它。
这是我是如何做到的:
Method m; // the method object
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(m.getDeclaringClass().getCanonicalName());
CtMethod javassistMethod = cc.getDeclaredMethod(m.getName());
int linenumber = javassistMethod.getMethodInfo().getLineNumber(0);
你无法从一个方法中获取行号,因为你不知道这个方法适用于哪个方法。一个方法可以调用你选择的任何子类。
javassist.NotFoundException
的问题,通过添加以下代码解决了该问题:ClassClassPath ccpath = new ClassClassPath(aJavaPipeline); pool.insertClassPath(ccpath);
- okrunnervoid foo()
\n{
\n// 有趣的注释
\nSystem.out.println("foo");
\n}
在我的情况下,上述解决方案即使没有注释也不会打印出声明的行号。 - pete83