如何获取使用 ASM 初始化对象的位置?



我有一个特定的类想要照顾。

public class TargetClass {
public TargetClass() { /* .. */ }
}

在我的大项目中,我有多个位置可以创建此类的新实例

public class A {
...
TargetClass obj = new TargetClass() // say line number 100
...
}
public class B {
...
TargetClass obj = new TargetClass() // say line number 200
...
}

如何使用 ASM 在构造函数中插入字段initLocation,当调用new TargetClass()时,initLocation 将记录 init 位置的行号,例如package/path/A + L100package/path/B + L200

这很简单:

ClassNode node = context.getInfo().getNode(); // You have to make ClassNode by yourself. 
for (MethodNode method : node.methods) {
int lineNumber = -1;
ListIterator<AbstractInsnNode> iter = method.instructions.iterator();
while (iter.hasNext()) {
AbstractInsnNode instruction = iter.next();
if (instruction instanceof MethodInsnNode) {
MethodInsnNode invokeInsn = (MethodInsnNode) instruction;
if (invokeInsn.getOpcode() == Opcodes.INVOKESPECIAL && invokeInsn.name.equals("<init>")) {
if (invokeInsn.owner.equals("Receiver")) { // Here we have to use internal class name. For example java.lang.Class = java/lang/Class
iter.previous();
iter.add(new InsnNode(Opcodes.DUP));
iter.next();
iter.add(new LdcInsnNode(node.name + " " + method.name + method.desc + " L" + lineNumber));
iter.add(new FieldInsnNode(Opcodes.PUTFIELD, "Receiver", "initializationInfo", "Ljava/lang/String;"));
}
}
} else if (instruction instanceof LineNumberNode) {
lineNumber = ((LineNumberNode) instruction).line;
}
}
}

我只是遍历每个方法中的每个指令。当我找到INVOKESPECIAL时,我将目标方法与<init>(构造函数的内部名称(进行比较,并将所有者名称与Receiver进行比较。您可能会将其替换为您自己的类的名称。 当所有这些条件都满足时,我在构造函数调用之前插入DUP指令,之后LDCPUTFIELD

测试类

public class Transmitter {
public static void main(String[] args) {
Receiver r = new Receiver();
System.out.println(r.initializationInfo);
}
}

结果

java -cp main Transmitter
Transmitter main([Ljava/lang/String;)V L4

相关内容

  • 没有找到相关文章

最新更新