さらにSeasar2を味わいまくってみる。

もっとSeasar2を味わってみる。 - 都元ダイスケ IT-PRESSの続き。

さっきのapp.diconって、ちょっとネスト深くて見通し悪いよね〜。

その前にまず、いい加減パッケージ分けしましたw

こんな感じで。

そしてapp.diconの見通しを良くしてみた。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components>
    <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
        <initMethod name="addClassPattern">
            <arg>"jp.xet.tutorial.s2.converter"</arg>
            <arg>".*"</arg>
        </initMethod>
    </component>

    <component class="jp.xet.tutorial.s2.Table">
        <arg>"T_HOGE"</arg>
        <property name="columns">{ column1, column2 }</property>
    </component>
    <component name="column2" class="jp.xet.tutorial.s2.Column">
        <arg>"ID"</arg>
        <arg>"integer"</arg>
    </component>
    <component name="column1" class="jp.xet.tutorial.s2.Column">
        <arg>"CONTENTS"</arg>
        <arg>"string"</arg>
    </component>

    <component name="mysqlBusiness" class="jp.xet.tutorial.s2.BusinessLogic">
        <arg>mySQLConverter</arg>
    </component>
    <component name="postgresqlBusiness" class="jp.xet.tutorial.s2.BusinessLogic">
        <arg>postgreSQLConverter</arg>
    </component>
</components>

さて、またわかんないのが出てきましたね。とりあえず上のブロックにある複雑そうなコンポーネントはスルーしときましょう。で、真ん中あたりのブロックががモデルの定義で、下のブロックがロジックの定義。

モデル定義部分のポイント解説

変わったのは、Table#columns の定義部分。中になんか「{ column1, column2 }」とか書いてある。これが、前回のエントリでスルーしたOGNLという表記方法の1つ。これ、column1とcolumn2のListなんです*1

あとは分かると思う。column1,column2コンポーネントが定義されてる。

ロジック定義部分のポイント解説

これも、前と変わんないよね〜。コンポーネント名が "mysql" から "mySQLConverter" に変わってるだけ...だけど、そもそもコンポーネント登録がされていなくね? (前エントリの、最後の2定義が消えている)

これもアノテーション登録なのだろうか、とMySQLConverterを見てみても、アノテーションは無い。っていうかComponentアノテーションさえも無い。

public class MySQLConverter implements Converter {
    // 同じなので略
}

それどころか、コード全体どこを見てもアノテーションが1つも無い。何事...orz

というのが今回のメイン話である「コンポーネント自動登録」

正直、そこまで空気読むか、と俺も思うw

最初にスルーした、上ブロックにある複雑そうなコンポーネント。これが鍵になる。

これは「jp.xet.tutorial.s2.converterパッケージにある、.*という名前(正規表現だから、全ての名前)のクラスは、勝手にコンテナに登録しとけやゴルァ」という指示。MySQLConverterとPostgreSQLConverterは、そういえばこのパッケージに置いてある。ということで、勝手に登録されたんですね。

では、そのコンポーネントの名前は? ここも空気を読むSeasar2、のターン。「クラス名の最初を小文字にした名前で、登録しとくお」。

ということで、mySQLConverterとpostgreSQLConverterというコンポーネントが、自動登録されました。

以上、軽くOGNLの話と、コンポーネント自動登録のお話でした。

ファイルまとめ。

最初のエントリから編集を続けて、かなり様変わりしてきたので、現状のコードを全て書いておきますね。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components>
    <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
        <initMethod name="addClassPattern">
            <arg>"jp.xet.tutorial.s2.converter"</arg>
            <arg>".*"</arg>
        </initMethod>
    </component>
    
    <component class="jp.xet.tutorial.s2.Table">
        <arg>"T_HOGE"</arg>
        <property name="columns">{ column1, column2 }</property>
    </component>
    <component name="column2" class="jp.xet.tutorial.s2.Column">
        <arg>"ID"</arg>
        <arg>"integer"</arg>
    </component>
    <component name="column1" class="jp.xet.tutorial.s2.Column">
        <arg>"CONTENTS"</arg>
        <arg>"string"</arg>
    </component>

    <component name="mysqlBusiness" class="jp.xet.tutorial.s2.BusinessLogic">
        <arg>postgreSQLConverter</arg>
    </component>
    <component name="postgresqlBusiness" class="jp.xet.tutorial.s2.BusinessLogic">
        <arg>postgreSQLConverter</arg>
    </component>
</components>
package jp.xet.tutorial.s2;

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

public class Main {
	
    public static void main(String[] args) {
        SingletonS2ContainerFactory.init();
        S2Container container = SingletonS2ContainerFactory.getContainer();
        
        Table table = (Table) container.getComponent(Table.class);
        BusinessLogic business = (BusinessLogic) container.getComponent("mysqlBusiness");
        business.doBusiness(table);
        
        container.destroy();
    }
}
package jp.xet.tutorial.s2;

import java.util.List;

public class Table {
    public String name;
    public List<Column> columns;

    public Table(String name) {
        this.name = name;
    }
}
package jp.xet.tutorial.s2;

public class Column {
    public String name;
    public String type;

    public Column(String name, String type) {
        this.name = name;
        this.type = type;
    }
}
package jp.xet.tutorial.s2;

public class BusinessLogic {
	
    private Converter converter;
    
    public BusinessLogic(Converter converter) {
        this.converter = converter;
    }

    public void doBusiness(Table table) {
            String sql = converter.convert(table);
            System.out.println(sql);
    }
}
package jp.xet.tutorial.s2;

public interface Converter {
	String convert(Table table);
}
package jp.xet.tutorial.s2.converter;

import jp.xet.tutorial.s2.Column;
import jp.xet.tutorial.s2.Converter;
import jp.xet.tutorial.s2.Table;

public class MySQLConverter implements Converter {
	
    public String convert(Table table) {
        StringBuilder sb = new StringBuilder();
        sb.append("CREATE TABLE ").append(table.name).append("(\n");
        for(Column column : table.columns) {
                sb.append("  ").append(column.name).append(" ");
                if("integer".equals(column.type)) {
                        sb.append("INT");
                } else if("string".equals(column.type)) {
                        sb.append("TEXT");
                } else {
                        sb.append(column.type);
                }
                sb.append(",\n");
        }
        sb.delete(sb.length()-2, sb.length()-1);
        sb.append(");\n");
        return sb.toString();
    }
}
package jp.xet.tutorial.s2.converter;

import jp.xet.tutorial.s2.Column;
import jp.xet.tutorial.s2.Converter;
import jp.xet.tutorial.s2.Table;

public class PostgreSQLConverter implements Converter {
	
    public String convert(Table table) {
        StringBuilder sb = new StringBuilder();
        sb.append("CREATE TABLE ").append(table.name).append("(\n");
        for(Column column : table.columns) {
                sb.append("  ").append(column.name).append(" ");
                if("integer".equals(column.type)) {
                        sb.append("INTEGER");
                } else if("string".equals(column.type)) {
                        sb.append("VARCHAR(32)");
                } else {
                        sb.append(column.type);
                }
                sb.append(",\n");
        }
        sb.delete(sb.length()-2, sb.length()-1);
        sb.append(");\n");
        return sb.toString();
}}

いやーー、いい復習になったわ(ぉ

*1:ちなみに「#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}」って書くとMapなんです。