他の人が作成したバイトコードを変更するために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 命令が"Lcom/example/ExampleClass;.class"
実際のクラスではなく文字列を追加しているためLcom/example/ExampleClass;.class
です。
これに対する回避策はありますか? クラスがまだ存在しないため、Class
オブジェクトを anに直接追加することは不可能のようです。しかし、オブジェクトLdcInsnNode
をロードする命令を追加する方法はありますか?Class
Object.getClass()
私の特定のケースでは、静的コンテキストから動作する必要があるため、メソッドを呼び出すことはオプションではありません。