さらにSeasar2を味わいまくってみる。
もっとSeasar2を味わってみる。 - 都元ダイスケ IT-PRESSの続き。
さっきのapp.diconって、ちょっとネスト深くて見通し悪いよね〜。
そして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なんです。