ASM指南通译-11 方法转换

ASM指南翻译-11 方法转换

 

3.2.3转换方法

现在,你已经猜到了,方法可以像类一样就行转换,例如,通过使用一个方法适配器来转发那些带有修改的方法调用:改变参数可以被用来变更指令,不转发某个方法调用可以删除一个指令,插入新的调用可以添加新的指令。MethodAdapter类提供了这样的基本实现,它仅仅转发它收到的所有方法调用。

 

为了弄清楚方法适配器如何使用,让我们考虑一个简单的例子,删除方法中的NOP指令(删除该指令不会带来任何问题,因为这个指令不做任何事情):

public class RemoveNopAdapter extends MethodAdapter {

         public RemoveNopAdapter(MethodVisitor mv) {

                   super(mv);

         }

         @Override

         public void visitInsn(int opcode) {

                   if (opcode != NOP) {

                            mv.visitInsn(opcode);

                   }

         }

}

 

这个适配器可以用在一个类适配器中,像下面一样:

public class RemoveNopClassAdapter extends ClassAdapter {

         public RemoveNopClassAdapter(ClassVisitor cv) {

                   super(cv);

         }

         @Override

         public MethodVisitor visitMethod(int access, String name,

                   String desc, String signature, String[] exceptions) {

                   MethodVisitor mv;

                   mv = cv.visitMethod(access, name, desc, signature, exceptions);

                   if (mv != null) {

                            mv = new RemoveNopAdapter(mv);

                   }

                   return mv;

         }

}

 

这个类适配器主要用来构建方法适配器,该适配器封装链上的下一个Class Visitor返回的方法适配器,然后返回该适配器。这个方法适配器链构造的效果类似于之前的类适配器链(参看图3.5)。

 

尽管上面的要求不是强制性的,但是仍然可能构造一个与类适配器链不同的方法适配器链。每个方法甚至都可以有一个不同的方法适配器链。例如,类适配器可以选择在方法中而不是构造方法中移除NOP指令。可以像下面这样来实现:

...

mv = cv.visitMethod(access, name, desc, signature, exceptions);

if (mv != null && !name.equals("<init>")) {

mv = new RemoveNopAdapter(mv);

}

...

 


ASM指南通译-11  方法转换

3.5 RemoveNopAdapter序列图

 

在这个例子中,针对构造方法的适配器链要短一些。相反地,针对构造方法的适配器链也可以更长,可以将几个方法适配器在visitMethod方法内部链接在一起。方法适配器链也可以拥有与类适配器链不同的拓扑图结构。例如,类适配器链应该是线性的,而方法适配器可以有分支:

public MethodVisitor visitMethod(int access, String name,

         String desc, String signature, String[] exceptions) {

         MethodVisitor mv1, mv2;

         mv1 = cv.visitMethod(access, name, desc, signature, exceptions);

         mv2 = cv.visitMethod(access, "_" + name, desc, signature, exceptions);

         return new MultiMethodAdapter(mv1, mv2);

}

 

现在,我们已经了解了如何在一个类适配器中使用方法适配器,以及如何组装它们,下面让我们来看看如何实现比RemoveNopAdapter更有趣的适配器。