修改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返回結(jié)果為Tiger

修改前getName方法對(duì)應(yīng)的java源碼

return name;

對(duì)應(yīng)的Bytecode

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

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

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

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

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

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

項(xiàng)目地址 https://github.com/jared-lin/JavassistSample

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容