当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

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

发表于: 2015-07-15   作者:lijingyao8206   来源:转载   浏览:
摘要:     同生成的做法一样,添加和移除类成员只要去修改fields和methods中的元素即可。这里我们拿一个简单的类做例子,下面这个Task类,我们来移除isNeedRemove方法,并且添加一个int 类型的addedField属性。   package asm.core; /** * Created by yunshen.ljy on 2015/6/

    同生成的做法一样,添加和移除类成员只要去修改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);
    }
}

 

 

 

 

 

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

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
之前一篇简单介绍了一下ASM框架。这一篇继续对CoreApi进行扩展。这里还是继续对ClassWriter ,Class
之前一篇简单介绍了一下ASM框架。这一篇继续对CoreApi进行扩展。这里还是继续对ClassWriter ,Class
之前一篇简单介绍了一下ASM框架。这一篇继续对CoreApi进行扩展。这里还是继续对ClassWriter ,Class
一、新建一个分类 二、加入属性 三、引入objc/runtime头文件 四、制定一个字符串 五、实现get,set方
  上文讲到了CSS3的选择器,通过after和before选择器,在元素前后添加内容。   也可以通过变量
内容:输入三个整数,输出它们的最大值 目的:初步掌握类和对象 程序代码: /* *程序的版权声明部分
我发现一旦稍稍体会到GEF的妙处,就会很自然的被它吸引住。不仅是因为用它做出的图形界面好看,更重
利用 SMS 实现操作系统的补丁分发 杜 飞 微软的每个操作系统都会不断的推出新的补丁,如Win2000的补
一、概述    ASM的CoreApi 中还提供了对class 中方法的生成和解析的组件。前面两篇着重介绍了Clas
一、概述    ASM的CoreApi 中还提供了对class 中方法的生成和解析的组件。前面两篇着重介绍了Clas
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号