记录执行的java代码的行号

时间:2012-06-01 16:05:32

标签: java php code-coverage

我正在编写PHP Web应用程序的一部分(将用于高中错误查找竞赛),其中用户必须在给定的Java程序中找到错误。作为其中的一部分,当Java程序执行时,我们想要突出显示代码已执行的Java程序源代码行。为此,我们需要的只是已执行的源代码行号,即代码路径(或称为代码覆盖率?)。我们将使用行号突出显示源文件中的行。

我们将使用PHP的shell-exec()来执行Java程序和工具来获取代码路径(无论是什么)。获取代码路径行号的最简单方法是什么?

非常感谢!

这是描述我们想要的内容的图片

enter image description here

5 个答案:

答案 0 :(得分:4)

PHP将代码插入代码,这意味着每次运行程序时它都会在源代码上运行。这有利于在读取代码时爆炸(这使得行号打印输出微不足道);但是,它在其他方面通常很昂贵,因为您无法进行深度优化(或进行任何运行前错误检查)。

Java compiles its code into a JVM assembly language called "bytecode."这意味着正在运行的内容通常无法访问(甚至使用)源代码。也就是说,有技术。已编译的Java类能够添加“额外数据”,其中一个“额外数据元素”为a line number table,这是一个允许运行程序集的人“查找”行号的索引编译器记录了它

这通常可以正常工作,考虑到:编译器通常不会标记每条指令,源代码可能不可用,优化可能会使某些内部代码块无法以便于指向输入代码的方式运行文本。

代码覆盖工具如何“修复”这是因为它们通常会在代码中(在程序集级别)插入大量命令,这些命令有效地充当一种格式的日志语句,允许工具确定通过代码的路径实际上是遵循。然后,尽可能将其映射回行号表,然后用于突出显示原始源文件中的行。

如果你想要一些具有更好分辨率的东西(可以处理一行的哪一部分被执行),那么你需要深入挖掘。最后,您甚至可以考虑编写自己的编译器(或编译器扩展),它将存储您自己的自定义行号表,以克服当前解决方案的缺点。

像抛出异常(如Shiven所提到的)和解析行号这样的技巧确实有效;然而,他们使用奇怪的异常处理来污染您的代码,这些异常处理不是例外,只是为了“获取行号”。由于代码混乱和异常的运行时性能通常较差,我倾向于避免使用这些解决方案(但它们确实有效)。

无论如何,希望这能让你了解为什么它的工作方式与PHP完全不同。

答案 1 :(得分:1)

看看Cobertura。它计算覆盖范围和类似的东西,如果它还没有这样做,那么添加收集的行号应该相对容易。 这样做有一种非常严厉的尝试,但这很慢,以至于你可能无法在生产中使用它https://bitbucket.org/jowu/myriapod/wiki/Home

答案 2 :(得分:0)

如果使用-g选项编译程序,执行printStackTrace(),捕获跟踪输出并从那里提取亚麻,则可以得到亚麻布。

答案 3 :(得分:0)

我从来没有做过或看过这样的事情,但它确实看起来像一个有趣的问题。我的想法是使用the java debugger (jdb)来运行代码,而不仅仅是java命令。

您可以逐行浏览代码(通过jdb中的step命令),每次执行一行代码时,都会吐出代码。这需要PHP方面的一点帮助(它必须解析行号以及执行下一步命令)但行号在那里。这是一个非常基本的java程序的示例输出。

Java(TestClass.java)

public class TestClass {
   public static void main(String[] args) {
      System.out.println("foo");
      System.out.println("bar");
   }
}

jdb(运行javac TestClass.java后的jdb TestClass)

Initializing jdb ...
> stop at TestClass:3
Deferring breakpoint TestClass:3.
It will be set after the class is loaded.
> run
run TestClass
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
> 
VM Started: Set deferred breakpoint TestClass:3

Breakpoint hit: "thread=main", TestClass.main(), line=3 bci=0
3          System.out.println("foo");

main[1] step
> foo

Step completed: "thread=main", TestClass.main(), line=4 bci=8
4          System.out.println("bar");

main[1] step
> bar

Step completed: "thread=main", TestClass.main(), line=5 bci=16
5        }

main[1] step
> 
The application exited

答案 4 :(得分:0)

尝试参考此链接JVMDI

您可以尝试访问程序计数器的值,然后将其映射到lineNumberTable。 要么 我认为JVMDI有一个方法可以访问执行代码的行号。我不确定后者,请参考上面的链接并希望它有所帮助。