-Threadlocalize

SeasarConのセッション中デモでやらなかったサンプル

@Threadlocalize private Foo field1 = new Foo();
field1 = var1;
field1.bar();

こういう風に、ユーザーコードの中で用意したメタアノテーションで修飾されたフィールドがあったとしたら、

private ThreadLocal<Foo> field1 = new ThreadLocal<Foo>(new Foo());
field1.set(var1);
field1.get().bar();

と書き換えちゃうプロセッサの例。

public class ThreadLocalizeProcessor {
    /**
     * @when   {@link ThreadLocalize} in self.annotations
     *         tl = {@link ThreadLocal}
     */
    public void processDecl(CtClass<ThreadLocal<?>> tl, CtField<?> self) {
        CtType<?> type = self.getType(); // フィールドの型を取得
        CtClass<?> ptl = tl.getParameterized(type); // ThreadLocalのタイプ引数にセット
        type.substitute(ptl); // フィールドの型宣言を書き換える
        CtExpression<?> init = self.getInitializer(); // 初期化子を取得
        if (init.exists()) { // 初期化子を引数に取るThereadLocalのコンストラクタ
            init.substitute(ptl.newInvocation(init)); 
        } else { // 引数無しのThreadLocalのコンストラクタをぶち込む
            init.substitute(ptl.newInvocation());
        }
    }
    /**
     * @when    self.leftHandSide = field;
     *          field = {@link CtField} // fieldは引数リストに無いためJavadoc内で型制約をつける
     *          {@link ThreadLocalize} in field.annotations
     *          set = {@link ThreadLocal#set(Object)} // メソッド定義を引っ張ってくる
     */
    public void processAssgin(CtAssignment<?, ?> self, CtMethod<?> set) {
        CtMethodInvocation<?> methodInvocation =
            set.newInvocation(self.getRightHandSide()); // フィールドアサインを置き換え
        methodInvocation.getQualifier().substitute(self.getLeftHandSide());
        // あ、「Qualifier」ってなじまないかな?メソッド呼び出しの主体のこと。
        self.substitute(methodInvocation);
    }
    /**
     * @when    self = field
     *          field = {@link CtField} // fieldは引数リストに無いためJavadoc内で型制約をつける
     *          {@link ThreadLocalize} in field.annotations
     *          get = {@link ThreadLocal#get()} // メソッド定義を引っ張ってくる
     */
    public void processUse(CtExpression<?> self, CtMethod<?> get) {
        CtMethodInvocation<?> methodInvocation = get.newInvocation();
        methodInvocation.getQualifier().substitute(self); // フィールド参照を置き換え
        self.substitute(methodInvocation);
    }
}

はじめのprocessDecl()でフィールド定義を冒頭例示のように書き換え、processAssgin()でフィールドへ値を設定している箇所全てをThreadLocal#set()に書き換えます。そして、processUse()でフィールドを読み出している箇所全てをThreadLocal#get()利用にするものです、これでコード全部です。ほらね、簡単でしょ?