javassistでHelloWorldをやってみる

Seasar2で使われているjavassistが気になったので、HelloWorld程度のサンプルを動かしてさくっと触ってみる。

javassistとは

javassistは「クラスのバイトコードを直接書き換える」ことができ、東京工業大学の千葉先生による純日本製の技術です。

このJavassistを利用することで、難しいバイトコードを意識することなくクラスのバイトコードを外部から操作できるようになります。

というわけで、カンタンなサンプルコードを書いてみるす。

準備

まずは、javassistのライブラリをDLします。
http://www.jboss.org/javassist/
最新版っぽい3.4GAをDLして解凍してできたフォルダ内のjavassist.jarにクラスパスを通す。

メッセージ表示クラス

package javassist;

public class HelloJavassist {
    public void showMessage() {
        System.out.println("Hello Javassist!!");
    }
}

メインクラス

MainクラスでHelloJavassist#showMessageを実行する際に、メソッド実行時の前と後ろにAOP的な処理を入れてみます。

package javassist;

public class Main {
    public static void main(String[] args) {
        try {
            ClassPool cp = ClassPool.getDefault();
            CtClass cc = cp.get("javassist.HelloJavassist");
            cc.stopPruning(true);
            CtMethod m = cc.getDeclaredMethod("showMessage");
            m.insertBefore("System.out.println(\"before statement\");");
            m.insertAfter("System.out.println(\"after statement\");");
            cc.writeFile();
            Class clazz = cc.toClass();
            HelloJavassist helloJavassist = (HelloJavassist) clazz.newInstance();
            helloJavassist.showMessage();
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
}

んで、Main.javaを実行すると

before statement
Hello Javassist!!
after statement

と表示される。おお〜!うまくAOP的なことができたね。

ここで注意しないといけないのはMain#mainに記述されている以下の箇所だ。

cc.stopPruning(true);

コイツを書くのを忘れていると、下のようなExceptionで怒られるので要注意!!

java.lang.RuntimeException: toBytecode(): javassist.HelloJavassist was pruned.
	at javassist.CtClassType.checkPruned(CtClassType.java:1284)
	at javassist.CtClassType.toBytecode(CtClassType.java:1245)
	at javassist.CtClass.toBytecode(CtClass.java:1181)
                             :
                             :