ASM系列六 利用TreeApi 添加和移除类成员

编程技术  /  houtizong 发布于 2年前   218

    同生成的做法一样,添加和移除类成员只要去修改fieldsmethods中的元素即可。这里我们拿一个简单的类做例子,下面这个Task类,我们来移除isNeedRemove方法,并且添加一个int 类型的addedField属性。

 

package asm.core;/** * Created by yunshen.ljy on 2015/6/8. */public class Task {    private int isTask = 0;    public void tellMe(){        System.out.println("call tellMe");    }    public void isNeedRemove(){        // do sth    }}

        首先我们可以构建一个Transformer用来处理ClassNode 中的fieldsmethods列表。为了方便维护和扩展,我们创建两个Transformer。一个RemoveMethodTransformer来移除方法,一个AddFieldTransformer来添加field

 

 

        读取Task的字节码,可以通过Core Api ClassReader,而且因为ClassNode继承了ClassVisitor,所以我们可以通过ClassReaderaccept方法来处理,这里依旧是将ClassReader当做一个生产者,ClassNode是消费者。而且,有趣的是,ClassNode也有一个accept方法,也就是说,可以传递本身的事件给一个ClassVisitor。这个ClassVisitor会继续“消费”所有ClassNode 属性中的事件。

 

        先来看一下RemoveMethodTransformer的实现:

package asm.tree;import org.objectweb.asm.tree.ClassNode;import org.objectweb.asm.tree.MethodNode;import java.util.Iterator;/** * Created by yunshen.ljy on 2015/7/12. */public class RemoveMethodTransformer {    private String fieldName;    private String fieldDesc;    public RemoveMethodTransformer(String fieldName, String fieldDesc) {        this.fieldName = fieldName;        this.fieldDesc = fieldDesc;    }    public void transform(ClassNode cn) {        Iterator<MethodNode> i = cn.methods.iterator();        while (i.hasNext()) {            MethodNode mn = i.next();            if (mn.name.equals(fieldName) ) {                i.remove();            }        }    }}

    可以看到transform方法利用迭代器来直接处理ClassNode对象的methods列表。下面再看一下AddFieldTransformer的实现。

package asm.tree;import org.objectweb.asm.tree.ClassNode;import org.objectweb.asm.tree.FieldNode;/** * Created by yunshen.ljy on 2015/7/12. */public class AddFieldTransformer   {    private int fieldAccess;    private String fieldName;    private String fieldDesc;    public AddFieldTransformer(int fieldAccess, String fieldName, String fieldDesc) {        this.fieldAccess = fieldAccess;        this.fieldName = fieldName;        this.fieldDesc = fieldDesc;    }    public void transform(ClassNode cn) {        boolean isPresent = false;        for (Object fn : cn.fields) {            FieldNode ff = (FieldNode) fn;            if (fieldName.equals(ff.name)) {                isPresent = true;                break;            }        }        if (!isPresent) {            cn.fields.add(new FieldNode(fieldAccess, fieldName, fieldDesc, null, null));        }    }}

    最后,测试并利用ClassWriter来输出处理后的二进制字节流。我们刚好可以利用ClassNodeaccept方法来让ClassWriter 能够Visit整个class,并且输出字节数组。

 ClassReader cr = new ClassReader("asm.core.Task");        ClassNode cn = new ClassNode();        cr.accept(cn,0);        RemoveMethodTransformer rt = new RemoveMethodTransformer("isNeedRemove","V");        rt.transform(cn);        AddFieldTransformer at= new AddFieldTransformer(Opcodes.ACC_PRIVATE,"addedField","I");        at.transform(cn);        ClassWriter cw = new ClassWriter(0);        cn.accept(cw);        byte[] toByte = cw.toByteArray();

    当然,也可以自己写一个Adapter,来封装ClassNode的处理。通过构造器来传递ClassWriter,如下,accept方法封装到visitEnd方法中,来绑定下一个消费事件:

public class MyClassAdapter extends ClassNode {    public MyClassAdapter(ClassVisitor cv) {        super(Opcodes.ASM4);        this.cv = cv;    }    @Override    public void visitEnd() {        accept(cv);    }}

   或者再增加一层代理来传递:

package asm.tree;import org.objectweb.asm.ClassVisitor;import org.objectweb.asm.Opcodes;import org.objectweb.asm.tree.ClassNode;/** * Created by yunshen.ljy on 2015/7/14. */public class MyClassAdapter extends ClassVisitor {    private ClassVisitor next;    public MyClassAdapter(ClassVisitor cv) {        super(Opcodes.ASM4,new ClassNode());        this.next = cv;    }    @Override    public void visitEnd() {        ClassNode cn = (ClassNode)cv;        cn.accept(cv);    }}

 

 

 

 

 

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客