言語はJavaでASM4.0
今回は既存のクラスに新しくメソッドを追加する。
検索して解決策をみつけたのでメモ。
SampleClassに新しく"public void foo() {}"を追加する。
おおまかな流れ
- byte配列が与えられる
- byte配列を用いてClassReaderのインスタンス生成
- ClassWriterのインスタンス生成
- ClassWriterを引数にClassVisitorのインスタンスを生成
- ClassVisitorのインスタンス生成時に無名クラスを用いてvisitEndのメソッドをオーバーライド
- 新しくメソッドを追加する
- ClassReader#acceptに、ClassVisitorに入れていたClassWriterのインスタンスを渡す
- ClassWriter#toByteArrayでbyte配列にする
// 元のファイル public class SampleClass { void f() {} }
// org.objectweb.asm.Opcodes内のstaticなフィールドを参照できる前提 public byte[] transform(byte[] bytes) { ClassReader cr = new ClassReader(bytes); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassVisitor cv = new ClassVisitor(ASM4, cw) { @Override public void visitEnd() { // メソッドを新しくつくる // ACC_PUBLICの部分を変えるとアクセサが変わる MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "foo", "()V", null, null); mv.visitMaxs(0, 0);// ClassWriterのCOMPUTE_MAXSのフラグをたてているので勝手に計算してくれる super.visiteEnd(); } }; cr.accept(cw, 0); return cw.toByteArray(); }
// 書き換え後 public class SampleClass { void f() {} public void foo() {} }
メソッドを追加したいときはvisitEndをいじる。
参考URL: