我正在使用ASM 库来修改其他人创建的字节码。对于任意类中的任意方法,我想创建一个LdcInsnNode
将当前类添加到堆栈中的方法。
例如,假设我正在转换一个名为com.example.ExampleClass
. 我想创建等效于System.out.println(ExampleClass.class.getName());
.
这似乎是一个相对简单的任务。当我使用 Eclipse Bytecode Outline 插件时,它说以下字节码是等效的:
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC Lcom/example/ExampleClass;.class
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
我尝试了以下代码:
private InsnList printClass() {
InsnList result = new InsnList();
result.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
result.add(new LdcInsnNode("L" + name + ";.class"));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false));
return result;
}
这是在 的扩展中运行的ClassNode
,因此name
指的是该ClassNode.name
字段。此InsnList
方法返回的 被插入到现有AbstractInsnNode
using之前InsnList.insertBefore(AbstractInsnNode, printClass())
。在字节码中达到这一点时,我收到一个错误,原因如下:
Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'java/lang/Class'
这显然是因为 LDC 指令添加的是 String"Lcom/example/ExampleClass;.class"
而不是实际的 class Lcom/example/ExampleClass;.class
。
有什么解决方法吗?似乎不可能直接将Class
对象添加到,LdcInsnNode
因为该类尚不存在。但是有没有办法添加一个加载Class
对象的指令?
在我的特殊情况下,调用该Object.getClass()
方法不是一种选择,因为它需要在静态上下文中工作。