SeasarBuilderの拡張

とりあえず#out.println("Hello")みたいなことをやりたくなったので挑戦。

MySeasarBuilder:SeasarBuilderを継承してみる。

import java.util.Map;

import org.seasar.framework.container.MethodDef;
import org.seasar.framework.container.impl.DestroyMethodDefImpl;
import org.seasar.framework.container.impl.InitMethodDefImpl;
import org.seasar.groovy.SeasarBuilder;

public class MySeasarBuilder extends SeasarBuilder {
        
    protected Object createNode(Object name, Map attributes) {
        if (name.equals("init")) {
            logger.debug("INIT; " + attributes);
            
            return setupMethodDef
                (new InitMethodDefImpl(), attributes);
        }        
        
        if (name.equals("destroy")) {
            logger.debug("DESTROY; " + attributes);
            
            return setupMethodDef
                (new DestroyMethodDefImpl(), attributes);
        }     
        
        return super.createNode(name, attributes);
    }    
    
    
    private MethodDef setupMethodDef(MethodDef def, Map attributes) {
        String referenceExpression 
            = (String) attributes.get("expression");
        def.setExpression(referenceExpression);

        return def;
    }
}


FooClient.groovy:groovyファイルはこんな風にした。式はinit(){ expression }のようにしてもよかったかもしれないけどSeasarBuilderのほうでやり方わからず。(instanceのタイプをouterにしたものを定義した。この場合もclassの指定をしないとおこられる)

import org.seasar.framework.aop.interceptors.*
import org.seasar.groovy.*
import taedium.study.inject.*

new MySeasarBuilder().components(){
    
    component(class: Integer, name:"integer") {
        arg(99999)
    }
    
    component(class: Foo, name:"foo", instance:"outer") {
        prop(name:"number", ref:"integer")
        init(expression:"#out.print('class name is ')")
        init(expression:"#out.println(#self.getClass().getName())")
    }
}


Foo:interface

public interface Foo {

    Number getNumber();
    void setNumber(Number number);

}


FooClient:Fooの実装クラスにDependencyをinjectする(実装クラスはNumber型のプロパティを持つだけにした)

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class FooClient  {
    private static final String PATH = 
        "taedium/study/inject/FooClient.groovy";    
    
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        
        Foo foohoge = new FooHoge();
        container.injectDependency(foohoge, "foo");
        System.out.println(foohoge.getNumber());
        
        Foo foobar = new FooBar();
        container.injectDependency(foobar, "foo");
        System.out.println(foobar.getNumber());        
        
        container.destroy();
    }
}


実行結果:initとinjectが実行されている

class name is taedium.study.inject.FooHoge
99999
class name is taedium.study.inject.FooBar
99999
  • instanceのタイプをouterにしたときはaspectが使えないということもあるのでinitで式が使えると便利なときがありそう。
  • injectDependencyしたときはプロパティの設定を自動バインディングしてくれなかった。してくれてもいいなと思う。 してくれていました。

追記:もう一回試してみたらこんな書き方ができるようにBuilder変更できた。

    component(class: Foo) {
        init() {
            expression("#out.print('hogehoge')")
        }
    }