cglib実習01

いまさらながら簡単なサンプルを作ってみる。

まずはinterceptされちゃうクラス。 aaa()の中からbbb()を呼んでみて、クラス内部からの呼び出しでInterceptorが効くのかどうかを見てみる。

package yamo;

public class Foo {
public void aaa() {
Util.log("<aaa> start");
bbb();
Util.log("<aaa> end");
}

public void bbb() {
Util.log("<bbb> start");
Util.log("<bbb> end");
}
}

次にinterceptorクラス。 対象メソッドの前後でinterceptor用のログを出力する。 MethodProxyの「invokeSuper」っていうネーミングあたりでinterceptorの仕組みを窺い知ることができる。

package yamo;

import java.lang.reflect.*;
import net.sf.cglib.proxy.*;

public class LogInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {

Object ret = null;
try {
Util.log(obj.getClass(), method, "start Intercepter");
if(!Modifier.isAbstract(method.getModifiers())) {
ret = proxy.invokeSuper(obj, args);
}
} finally {
Util.log(obj.getClass(), method, "end Intercepter");
}

return ret;
}
}

そしてログ用のユーティリティクラス。

package yamo;

import java.lang.reflect.*;

public final class Util {
public static void log(Class clazz, Method method, String msg) {
log("[" + clazz.getName() +"][" + method.getName() + "]" + msg);
}

public static void log(String msg) {
System.out.println(msg);
}
}

いよいよメイン処理のクラス。

package yamo;

import net.sf.cglib.proxy.*;

public class Main {
public static void main(String[] args) {
Foo foo = (Foo)newInstance(Foo.class);
Util.log("========================================");
Util.log("<<" + foo.getClass().getName() + ">>");
Util.log("========================================");
foo.aaa();

foo = new Foo();
Util.log("========================================");
Util.log("<<" + foo.getClass().getName() + ">>");
Util.log("========================================");
foo.aaa();
}

public static Object newInstance(Class clazz) {
try {
LogInterceptor interceptor = new LogInterceptor();
Enhancer en = new Enhancer();
en.setSuperclass(clazz);
en.setCallback(interceptor);
Object target = en.create();
return target;
} catch(Throwable e) {
e.printStackTrace();
throw new Error(e.getMessage());
}
}
}

で、最後に実行結果。

========================================
<<yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf>>
========================================
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][aaa]start Intercepter
<aaa> start
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][bbb]start Intercepter
<bbb> start
<bbb> end
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][bbb]end Intercepter
<aaa> end
[yamo.Foo$$EnhancerByCGLIB$$ccaf9ecf][aaa]end Intercepter
========================================
<<yamo.Foo>>
========================================
<aaa> start
<bbb> start
<bbb> end
<aaa> end
「クラスEnhancer越しに生成したインスタンスはFooを拡張したクラスのインスタンスであり、クラスの内部でメソッドを呼んだ場合でもきちんとinterceptされる」ということですね。

教訓:はてなダイアリーに載せるつもりなら「<」とか「>」の使用は避けよう

「javadoc」と「修正履歴」

なんか、この日記のリンク元一覧にMSNの検索画面から「javadoc」と「修正履歴」で飛んで来たログが残ってる。
Googleとかで検索するといっぱい引っかかるのだけれど、MSNだとこの日記しか引っかからないらしい。
それなのに「javadoc」と「修正履歴」という単語を使ってはいるものの、「javadocにおける修正履歴」に関する情報は全く含まれていないので、ちょっと申し訳ない気になる。
なので、ちょっぴり「javadocにおける修正履歴」の話をば。

        • -

えっと、まず、J2SE1.4 SDK付属のjavadoc自体には修正履歴に関するタグはありません。
「@version」タグでバージョンを明示し、一般的なドキュメンテーションコメントとして任意の形式で履歴を残すという方法が妥当と思われます。
また、どうしてもタグで指定したいという場合にはjavadocを自作のカスタムドックレットで拡張することも可能です。
カスタムドックレットの詳細については下記URLを参照して下さい。

J2SE1.4 SDK付属のjavadocの説明(Win32用) http://java.sun.com/j2se/1.4/ja/docs/ja/tooldocs/win32/javadoc.html

J2SE1.4のJavadocのドックレットとかタグレットの説明 http://java.sun.com/j2se/1.4/ja/docs/ja/tooldocs/javadoc/index.html

また、javadocから目を離して修正履歴だけを考えた場合、CVSSubversion等のバージョン管理ツールを使うことによって、ソースファイルの外部に(擬似的に)修正履歴の管理を委譲することが出来ます。
これらのツールは、任意のバージョンのファイルを指定して差分を出力することが出来ますので、コメントによる修正履歴よりも詳細に変更点を知ることが出来ます(ただし、その変更に対する「意味」は別途明記する必要があります)。

……こんな感じでいいでしょうか。

アンガールズ

アンガールズは細いのではなく長いのですか。
そうですか。

追記01(2004/05/29 20:52)
アンガールズ」って書いてから数分で「アンガールズ」のキーワードから18件の参照がありました。なんらかの情報を期待して来た方、何も無くてごめんなさい。

追記02(2004/05/29 20:56)
参照がどんどん増えてく。
こわいよう。