我有一个特定的类想要照顾。
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 + L100
、package/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
指令,之后LDC
和PUTFIELD
。
测试类
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