Javassistを使用して.classファイルを変更する


最近再びを見て、JAVAのコンパイルしたバイトコードの構造に対してとても興味があって、ツールを探して.classファイルに対して行って解析して調べることができることを望みます.見つかりませんでした.javaassistはバイトコードを操作して変更できることがわかりました.このツールはJBOSSプロジェクトの一部であり、JBOSSはAOPを実現する基礎である.ほほほ、視野を広げて、もとは私达は直接バイトコードのファイルに対して修正することができて、たとえソースのファイルを知らないとしても(反コンパイルと全く异なります).簡単な例:
import javassist.*;
class Hello {
    public void say() {
        System.out.println("Hello");
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("Hello");
        CtMethod m = cc.getDeclaredMethod("say");
        m.setBody("{System.out.println(/"/");}");
        m.insertBefore("System.out.println(/"/");");
        Class c = cc.toClass();
        Hello h = (Hello)c.newInstance();
        h.say();
    }
}
このファイルをコンパイルして実行し、出力:
僕らは
CtMethod m = cc.getDeclaredMethod("say");
  m.setBody("{System.out.println(/"/");}");

  m.insertBefore("System.out.println(/"/");");
say()メソッドを変更し、
System.out.println("");

System.out.println("");
ここのClassPoolはCtClassのコンテナで、classファイルを読み取り、必要に応じてCtClassの構造を保存して後で使用します.デフォルトでは、現在のクラス・マウントから取得されます.もちろん、次のように指定できます.
pool.insertClassPath("/usr/local/javalib");
もちろん、メソッドを変更するだけでなく、makeClass()メソッドなどのclassを新規作成することもできます.
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");
には、sampleの例と同様に、新しい方法も追加できます.
package sample;

import javassist.*;
import java.lang.reflect.*;

/*
   A very simple sample program

   This program overwrites sample/Test.class (the class file of this
   class itself) for adding a method g().  If the method g() is not
   defined in class Test, then this program adds a copy of
   f() to the class Test with name g().  Otherwise, this program does
   not modify sample/Test.class at all.

   To see the modified class definition, execute:

   % javap sample.Test

   after running this program.
*/
public class Test {
    public int f(int i) {
     i++;
    return i;
    }

    public static void main(String[] args) throws Exception {
 ClassPool pool = ClassPool.getDefault();

 CtClass cc = pool.get("sample.Test");
 Test test=new Test();
 Class c=test.getClass();
 Method []method=c.getDeclaredMethods();
 for(int i=0;i<method.length;i++){
  System.out.println(method[i]);
 }
 try {
     cc.getDeclaredMethod("g");
     System.out.println("g() is already defined in sample.Test.");
 }
 catch (NotFoundException e) {
     /* getDeclaredMethod() throws an exception if g()
      * is not defined in sample.Test.
      */
     CtMethod fMethod = cc.getDeclaredMethod("f");
     CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);
     cc.addMethod(gMethod);
     cc.writeFile(); // update the class file
     System.out.println("g() was added.");
 }
    }
}
初回稼働時、Testにg()メソッドがないため、実行
CtMethod fMethod = cc.getDeclaredMethod("f");
     CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);  // f     g
     cc.addMethod(gMethod);
     cc.writeFile(); //  class  

     System.out.println("g() was added.");
印刷:g()was added
2回目の実行時には、上記の手順でclassファイルにgメソッドを追加したため、
System.out.println("g() is already defined in sample.Test.");
印刷:g()is already defined in sample.Test
Javassistは自分のclassファイルを修正できるだけでなく、JDKが持っているクラスライブラリも同様に修正できます(くだらない話、クラスライブラリも人が書いた^^)具体的にはtutorialを見てください.