【问题标题】:How to get the line number of a method?如何获取方法的行号?
【发布时间】:2012-10-11 08:02:56
【问题描述】:

是否可以使用反射或其他魔法获取方法的行号?
如果该方法在当前 Stacktrace 中,则有可能。使用Thread.currentThread().getStackTrace(),可以得到StackTraceElement 的行号。但是如果我只有java.lang.reflect.Method 对象,我该怎么办?

我发现了这个,用于类-> How to get source file-name/line-number from a java.lang.Class object 但它对方法没有用。

【问题讨论】:

    标签: java reflection


    【解决方案1】:

    我想做同样的事情,经过一些研究,我选择了 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");
        }
    }
    

    输出method x is on line 12 在我的情况下是准确的,我删掉了一些 cmets...

    注意:正如Pete83在cmets中提到的,这个方法实际上返回的是方法中的第一行代码,而不是声明方法的那一行。这通常不会成为问题,因为大多数人可能希望建立相对位置(声明它们的顺序)并将此信息用于您自己的约定。每当您觉得需要在注释中包含一个序数值时,就会出现这种情况,这可以很容易地由代码本身中的位置确定。


    快速参考 javassist 的 Maven 坐标:
    <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>
    

    【讨论】:

    • 听起来是个好主意!如果涉及多个类加载器,我希望它仍然有效。当我再次找到我的用例时,我会尝试它......
    • 在我的例子中,我想按照 Entity 对象中显示的顺序输出 ORM 实体信息。它们出现在实体中的顺序对于显示该实体的表来说是一个很好的顺序,这似乎是合理的。为此,我找到了所有的 getter 并将它们加载到 TreeMap 中,整数是行号,String 是 getter(实际上是因为我将如何使用 EL 获取值,我处理了getters 到属性名称中,即删除“get”并将第一个字符小写)。因为我希望这个过程很快......
    • 在启动时会创建一个实体类映射,它映射到这些现在已排序的属性的数组列表,因此我可以使用这个 entityFormat 对象,而无需太多开销。我读过其他人想要这样做,并建议他们使用注释,但我认为注释最好用于覆盖约定。完成后,它工作得很好,我认为每个指定序数的实体类上的注释真的很烦人。
    • 值得一提的是,我遇到了javassist.NotFoundException,通过添加解决了这个问题:ClassClassPath ccpath = new ClassClassPath(aJavaPipeline); pool.insertClassPath(ccpath);
    • @YachithaSandaruwan 我认为这是方法的偏移量,0 是方法的第一行...如果您指定超出范围的索引,则它返回-1。见:javassist.org/html/javassist/bytecode/…
    【解决方案2】:

    对我来说,指向 Javassist 的 Quaternion 的答案是这个问题的完美解决方案。 它适用于我,你也可以在只获取 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);
    

    【讨论】:

    • 很高兴听到!我很惊讶越来越多的人不想要这种功能。顺便说一句,我的用例是在网页上为自动生成的表格创建智能订单。你能分享一下你的情况吗?
    • 是的,当然。我的用例是从 AspectJ Reflection API 的一个方面获取所有建议。每个通知里面都有一个方法对象。我使用方法对象的行号对出现在方面源代码中的建议进行排序。建议的顺序对于调用非常重要。
    【解决方案3】:

    您无法从方法中获取行号,因为您不知道这适用于哪种方法。方法可以调用您选择的方法的任何子类。

    【讨论】:

    • 但是如果我也有实例呢?我可以从中获取类对象。在类文件中有一些调试信息/行号。所以从技术上讲,它应该以某种方式成为可能。
    • 在这种情况下是这样。您可以使用 ASM、BCEL、Javassist 等库读取字节码并提取字节码中的第一行。
    猜你喜欢
    • 1970-01-01
    • 2013-10-07
    • 2015-09-16
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    相关资源
    最近更新 更多