如何使用 java ASM 确定方法的行号?
How to determine line number for the method with java ASM?
我需要使用 ObjectWeb ASM 库确定 class 中特定方法的行号。
方法声明的行号或方法主体中的第一行同样被接受为正确答案(示例中为 6 或 7)。
示例:
1. public class Foo {
...
6. public void bar() {
7. try {
8. try {
9. System.out.println(); //first executable line
我尝试使用 MethodVisitor 的 visitLineNumber 方法,但它只访问第一个可执行行(示例中的第 9 行)。
我在 JavaAssist 库 (link) 上找到了这个问题的解决方案。
但是有没有办法用 ASM 解决这个问题?
编辑:
以下代码片段给出了相同的结果,第 9 行而不是第 6 或 7 行。
public static int getLineNumber(String path) throws IOException {
final File f = new File(path);
try (FileInputStream fis = new FileInputStream(f)) {
ClassReader reader = new ClassReader(fis);
ClassNode clNode = new ClassNode(Opcodes.ASM5);
reader.accept(clNode, Opcodes.ASM5);
for (MethodNode mNode : (List<MethodNode>) clNode.methods) {
if (mNode.name.equals("bar")) {
ListIterator<AbstractInsnNode> it = mNode.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode inNode = it.next();
if (inNode instanceof LineNumberNode) {
return ((LineNumberNode) inNode).line;
}
}
}
}
}
return -1;
}
public static LineNumberNode findLineNumberForInstruction(InsnList
insnList, AbstractInsnNode insnNode) {
Validate.notNull(insnList);
Validate.notNull(insnNode);
int idx = insnList.indexOf(insnNode);
Validate.isTrue(idx != -1);
// Get index of labels and insnNode within method
ListIterator<AbstractInsnNode> insnIt = insnList.iterator(idx);
while (insnIt.hasPrevious()) {
AbstractInsnNode node = insnIt.previous();
if (node instanceof LineNumberNode) {
return (LineNumberNode) node;
}
}
return null;
}
任何字节码处理库提供的行号都是基于LineNumberTable
attribute将方法的可执行指令映射到行号。所以这是一个基本的限制,你不能在 class 文件中找到不会导致生成可执行字节代码的源代码行。
有时甚至取决于编译器,将跨多行的构造分配给哪个源代码行。
我需要使用 ObjectWeb ASM 库确定 class 中特定方法的行号。
方法声明的行号或方法主体中的第一行同样被接受为正确答案(示例中为 6 或 7)。
示例:
1. public class Foo {
...
6. public void bar() {
7. try {
8. try {
9. System.out.println(); //first executable line
我尝试使用 MethodVisitor 的 visitLineNumber 方法,但它只访问第一个可执行行(示例中的第 9 行)。
我在 JavaAssist 库 (link) 上找到了这个问题的解决方案。
但是有没有办法用 ASM 解决这个问题?
编辑:
以下代码片段给出了相同的结果,第 9 行而不是第 6 或 7 行。
public static int getLineNumber(String path) throws IOException {
final File f = new File(path);
try (FileInputStream fis = new FileInputStream(f)) {
ClassReader reader = new ClassReader(fis);
ClassNode clNode = new ClassNode(Opcodes.ASM5);
reader.accept(clNode, Opcodes.ASM5);
for (MethodNode mNode : (List<MethodNode>) clNode.methods) {
if (mNode.name.equals("bar")) {
ListIterator<AbstractInsnNode> it = mNode.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode inNode = it.next();
if (inNode instanceof LineNumberNode) {
return ((LineNumberNode) inNode).line;
}
}
}
}
}
return -1;
}
public static LineNumberNode findLineNumberForInstruction(InsnList
insnList, AbstractInsnNode insnNode) {
Validate.notNull(insnList);
Validate.notNull(insnNode);
int idx = insnList.indexOf(insnNode);
Validate.isTrue(idx != -1);
// Get index of labels and insnNode within method
ListIterator<AbstractInsnNode> insnIt = insnList.iterator(idx);
while (insnIt.hasPrevious()) {
AbstractInsnNode node = insnIt.previous();
if (node instanceof LineNumberNode) {
return (LineNumberNode) node;
}
}
return null;
}
任何字节码处理库提供的行号都是基于LineNumberTable
attribute将方法的可执行指令映射到行号。所以这是一个基本的限制,你不能在 class 文件中找到不会导致生成可执行字节代码的源代码行。
有时甚至取决于编译器,将跨多行的构造分配给哪个源代码行。