修改class文件 (一)

com.jaredlin.sample.Animal.java

public class Animal {
    private String name;

    public String getName() {
        return name;
    }

    public Animal setName(String name) {
        this.name = name;
        return this;
    }

    public void run() {
        System.out.println("My name is "+name+",I'm running");
    }

    @Override
    public String toString() {
        return this.name;
    }
}

使用jclasslib bytecode viewer 查看class文件

addField

public static void addField(){
    ClassPool pool = ClassPool.getDefault();
    try {
        CtClass ctClass = pool.get("com.jaredlin.sample.Animal");
        Utils.rename(ctClass,"AddField");
        CtClass type = ClassPool.getDefault().get("java.lang.String");
        CtField f = new CtField(type,"weight",ctClass);
        CtField.Initializer init = CtField.Initializer.constant("3kg");
        ctClass.addField(f,init);
        ctClass.writeFile();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void addField2() {
    ClassPool pool = ClassPool.getDefault();
    try {
        CtClass ctClass = pool.get("com.jaredlin.sample.Animal");
        CtField ctField = CtField.make("private String weight=\"3kg\";",ctClass);
        ctClass.addField(ctField);
        ctClass.setName("AddField2");
        ctClass.writeFile();
    } catch (NotFoundException e) {
        e.printStackTrace();
    } catch (CannotCompileException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

修改getName返回結果為Tiger

修改前getName方法對應的java源碼

return name;

對應的Bytecode

其中 #2 表示獲取到 Constant Pool 中的第二項 (Bytecode中的方法getfield必須獲取的是CONSTANT_Fieldref_info) , 每行前面的紅色數字表示當前這一行byte的起始位置 (后面修改的時候要用到 , 后面要修改的byte的index是3) .

為了使得getName方法的Bytecode改動量最小 , 需要新增一個field值為 "Tiger" 并直接替換為#2的位置 , 代碼如下 (新增tiger , 查看ConstantPool確認tiger的序號 , 添加修改方法 ):

public static void changeReturn() {
     ClassPool pool = ClassPool.getDefault();
     try {
         CtClass ctClass = pool.getAndRename("com.jaredlin.sample.Animal","ChangeReturn");
         Utils.addStringField(ctClass,"tiger","Tiger");

         //修改方法開始 (修改方法需要新增的field在ConstantPool中的序號后執行)
         CtMethod method = ctClass.getDeclaredMethod("getName");
         CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();
         CodeIterator iterator = codeAttribute.iterator();
         iterator.writeByte(57, 3);//tiger在ConstantPool中的序號
         //修改方法結束

         ctClass.writeFile();
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

參考 : http://www.cnblogs.com/sunfie/p/5154246.html

項目地址 https://github.com/jared-lin/JavassistSample

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容