| # S2Dxo ## 目次 S2Dxo とは クイックスタート DXOの定義 インタフェース／クラス定義 メソッド定義 インターセプタの適用 変換ルール JavaBeansのプロパティとpublicフィールド 変換の基本 型変換 ネストしたJavaBeansのプロパティ 変換のカスタマイズ 変換元プロパティ名の指定 OGNL式の利用 `null`のプロパティを変換から除外する 空白文字列のプロパティを変換から除外する プレフィックス付きのプロパティ 日付・時刻のフォーマット 独自のコンバータ シャローコピー ## S2Dxo とは DXO (Data eXchange Object) とは，JavaBeansとJavaBeansまたはJavaBeansとMapを相互変換 (exchange) することを目的としたオブジェクトです．主な用途としては，プレゼンテーション層のモデル (ページ) とドメイン層のモデル (エンティティ) を相互変換することを意図しています． S2DxoはDXOを実現するためのフレームワークです．S2Dxoを使うと，Javaインタフェースを定義するだけでDXOを実現することが可能となります． ## クイックスタート さっそく試してみましょう．登場人物は次のようになります． 変換元のJavaBeans EmployeeとDepartmentの二つ．EmployeeはDepartmentを参照します． 変換先のJavaBeans EmployeePage．EmployeePageはEmployeeとDepartmentの両方のプロパティを持っています． 変換を行うDXO EmployeeDxo．EmployeeとDepartmentをEmployeePageに変換するDXOのJavaインタフェースです． S2Dxoは，上記3つのJavaBeansに対して，以下の図のような変換を行います． ##### Employee.java 変換元のJavaBeansです．Departmentを参照します．
    package examples.dxo;

    public class Employee {
        private String ename;
        private Department department;

        public String getEname() {
            return ename;
        }

        public void setEname(String ename) {
            this.ename = ename;
        }

        public Department getDepartment() {
            return department;
        }

        public void setDepartment(Department department) {
            this.department = department;
        }
    }
##### Department.java 変換元のJavaBeansです．Employeeから参照されます．
    package examples.dxo;

    public class Department {
        private String dname;

        public String getDname() {
            return dname;
        }

        public void setDname(String dname) {
            this.dname = dname;
        }
    }
##### EmployeePage.java 変換先のJavaBeansです．Employeeのプロパティenameに加えて，Departmentのプロパティdnameも持っています．toString()メソッドではこの二つのプロパティを文字列化しています．
    package examples.dxo;

    public class EmployeePage {
        private String ename;
        private String dname;

        public String getEname() {
            return ename;
        }

        public void setEname(String ename) {
            this.ename = ename;
        }

        public String getDname() {
            return dname;
        }

        public void setDname(String dname) {
            this.dname = dname;
        }

        public String toString() {
            return "employee : " + ename + ", department : " + dname;
        }
    }
##### EmployeeDxo.java 変換を行うDXOです．引数として変換元のJavaBeansであるEmployeeを受け取り，戻り値として変換先のJavaBeansであるEmployeePageを返します．単なるJavaインタフェースで実装がないことに注目してください．
    package examples.dxo;

    public interface EmployeeDxo {
        EmployeePage convert(Employee employee);
    }
##### app.dicon EmployeeDxoを利用するために必要な設定を記述します．
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
        "http://www.seasar.org/dtd/components24.dtd">
    <components>
        <include path="dxo.dicon"/>

            <component class="examples.dxo.EmployeeDxo">
                    <aspect>dxo.interceptor</aspect>
            </component>
    </components>
##### DxoMain.java サンプルを実行するためのクラスです．S2コンテナを初期化した後，変換元のJavaBeansを準備しています．それをS2コンテナから取得したDXOを使って変換しています．
    package examples.dxo;

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

    public class DxoMain {

        public static void main(String[] args) {
            SingletonS2ContainerFactory.setConfigPath("examples/dxo/app.dicon");
            SingletonS2ContainerFactory.init();
            S2Container container = SingletonS2ContainerFactory.getContainer();

            Employee employee = new Employee();
            employee.setEname("Mike");
            Department department = new Department();
            department.setDname("Sales");
            employee.setDepartment(department);

            EmployeeDxo dxo = (EmployeeDxo) container
                    .getComponent(EmployeeDxo.class);
            EmployeePage page = dxo.convert(employee);
            System.out.println(page);
        }
    }
##### 実行結果 DxoMainの実行結果は以下のようになります．EmployeeとDepartmentのプロパティがEmployeePageに設定されたことが分かります．
    employee : Mike, department : Sales
このサンプルはSeasar2.4配布ファイルのexamplesに含まれています． ## DXOの定義 ### インタフェース／クラス定義 DXOは通常Javaインタフェースとして定義します．抽象クラスとして定義することもできますが，S2Dxoが適用されるのは抽象メソッドのみとなります． 次のようになります．
    publi interface FooDxo {
        ・・・
    }
SMART deployを使用する場合，DXOのパッケージ名およびクラス名はSMART deployの規約に従ってください．SMART deployについては「Seasr2.4の新機能－SMART deploy」を参照してください． ### メソッド定義 DXOには変換を行うメソッドを定義します．メソッド名は自由ですが，慣例として`convert`で始めます． DXOのメソッドは次の2つの形式のいずれかにすることができます． 変換先型 メソッド名(変換元型) void メソッド名(変換元型, 変換先型) 戻り値が変換後型の場合はS2Dxoが変換後のインスタンスを生成して返します．戻り値型がvoidの場合は第2引数で受け取ったインスタンスを更新します． 変換前及び変換後の型の組み合わせは次のものがサポートされています．
変換前型 | 変換後型
--- | ---
JavaBeans | JavaBeans
JavaBeans[] | JavaBeans[]
JavaBeans | `java.util.Map`
JavaBeans[] | `java.util.Map[]`
`java.util.Map` | JavaBeans
`java.util.Map[]` | JavaBeans[]
例えば次のようになります．
    public interface FooDxo {
        ToBean convertBeanToBean(FromBean fromBean);
        void convertBeanToBean(FromBean[] fromBeans, ToBean[] toBeans);

        Map convertBeanToMap(FromBean fromBean);
        void convertBeanToMap(FromBean[] fromBeans, Map[] toMaps);

        ToBean convertMapToBean(Map fromMap);
        void convertMapToBean(Map[] fromMaps, ToBean[] toBeans);
    }
Java5のGenericsを使うとJavaBeansまたはMapのListもサポートされます．
変換前型 | 変換後型
--- | ---
JavaBeans[] | `java.util.List<`JavaBeans`>`
`java.util.List<`JavaBeans`>` | JavaBeans[]
`java.util.List<`JavaBeans`>` | `java.util.List<`JavaBeans`>`
JavaBeans[] | `java.util.List<java.util.Map>`
`java.util.List<`JavaBeans`>` | `java.util.Map[]`
`java.util.List<`JavaBeans`>` | `java.util.List<java.util.Map>`
`java.util.Map[]` | `java.util.List<`JavaBeans`>`
`java.util.List<java.util.Map>` | JavaBeans[]
`java.util.List<java.util.Map>` | `java.util.List<`JavaBeans`>`
例えば次のようになります．
    public interface BarDxo {
        List<ToBean> convert(FromBean[] fromBeans);
        Map[] convert(List<FromBean> fromBeans);
        List<ToBean> convert(List<Map> fromMaps);
    }
Mapの型引数を指定することもできます．キーの型はStringまたはStringを代入可能な型のみ有効です．値の型は任意の型を指定することができます．変換元の値が型引数で指定された型に代入できない場合は型変換が行われます． 例えば次のようになります．
    public interface BarDxo {
        Map<String, String> convert(FromBean fromBean);
        List<Map<String, String> convert(FromBean[] fromBeans);
    }
### インターセプタの適用 DXOインタフェース／クラスにはS2Dxoの提供するインターセプタを適用します．
    <include path="dxo.dicon"/>

    <component class="examples.dxo.FooDxo">
        <aspect>dxo.interceptor</aspect>
    </component>
SMART deployを使用する場合は，`app.dicon`で`dxo.dicon`をインクルードし，`customizer.dicon`に記述されている`dxoCustomizer`の設定を次のようにします．
    <component name="dxoCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
        <initMethod name="addCustomizer">
            <arg>defaultCustomizer</arg>
        </initMethod>
        <initMethod name="addCustomizer">
            <arg>
                <component class="org.seasar.framework.container.customizer.AspectCustomizer">
                    <property name="interceptorName">"dxo.interceptor"</property>
                </component>
            </arg>
        </initMethod>
    </component>
Customizerの詳細は「Seasr2.4の新機能－SMART deploy」を参照してください． ## 変換ルール ### JavaBeansのプロパティとpublicフィールド Seasar2は，2.4.17からpublicフィールドをプロパティとして扱う機能をサポートしています．S2Dxoもpublicフィールドをサポートします．本ドキュメントにおける「プロパティ」は，JavaBeans本来のgetter/setterメソッドによるプロパティに加えて，publicフィールドも含みます． ### 変換の基本 JavaBeansまたはMapからJavaBeansに変換する場合，変換先となるJavaBeansのプロパティを変換元から探し，(必要なら)型変換を行って変換先のプロパティに設定します． JavaBeansからMapに変換する場合は，変換元のJavaBeansの全プロパティについて変換先のMapに追加します．追加されるエントリのキーは変換元のプロパティ名(`String`)，値は変換元のプロパティ値です． ### 型変換 変換元と変換先の型が異なる場合は型変換が行われます．S2Dxoが標準で提供する型変換は以下の通りです．変換先の型を基準に参照してください．
変換元の型 | 変換先の型 | 説明
--- | --- | ---
`boolean/Boolean` | `boolean/Boolean` | -
`Number` | 数値が`1`より大きければ`true`，そうでなければ`false`に変換します．
その他任意の型 | 変換元を文字列化し，それが`"yes"`，`"y"`，`"true"`，`"on"`，`"1"`のいずれかであれば`true`，そうでなければ`false`に変換します．
`boolean/Boolean` | `byte/Byte` `short/Short` `int/Integer` `long/Long` `float/Float` `double/Double` `java.math.BigDecimal` `java.math.BigInteger` | 変換元が`true`なら`1`，そうでなければ`0`に変換します．
`Number` | 同等の値に変換します． プリミティブ型への変換は，`Number#xxxValue()`で行われます． BigDecimal/BigIntegerへの変換は，変換元を文字列化したものをコンストラクタ引数に渡すことで行われます．
`String` | 文字列の表現する数値と同等の値に変換します．
`Enum`のサブクラス | 列挙定数の序数に変換します (S2-Tigerが必要です)． 序数への変換は`Enum#ordinal()`で行われます．
`char/Character` | `char/Character` | -
`String` | `String` | -
`char[]` | 変換元を文字シーケンスとして持つ`String`に変換します．
`Enum`のサブクラス | 列挙定数の名前に変換します (S2-Tigerが必要です)． 列挙定数への変換は`Enum#name()`で行われます．
`java.util.Calender` `java.util.Date` `java.sql.Date` | `DATE_PATTERN`フォーマットに従い変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.sql.Time` | `TIME_PATTERN`フォーマットに従い変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.sql.Timestamp` | `TIMESTAMP_PATTERN`フォーマットに従い変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
その他任意の型 | 変換元の文字列表現の持つ文字配列に変換します．
`char[]` | `char[]` | -
`String` | 変換元の持つ文字配列に変換します．
その他任意の型 | 変換元の文字列表現に変換します．
`java.util.Calendar` | `java.util.Calendar` | -
`java.util.Date` | 変換元の時刻値を持つ`java.util.Calendar`に変換します．
`Number` | 変換元の`long`値を時刻値として持つ`java.util.Calendar`に変換します．
`String` | `DATE_PATTERN`フォーマットに従い`java.util.Calendar`に変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.util.Date` | `java.util.Date` | -
`java.util.Calendar` | 変換元の時刻値を持つ`java.util.Date`に変換します．
`Number` | 変換元の`long`値を時刻値として持つ`java.util.Date`に変換します．
`String` | `DATE_PATTERN`フォーマットに従い`java.util.Date`に変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.sql.Date` | `java.sql.Date` | -
`java.util.Date` | 変換元の時刻値を持つ`java.sql.Date`に変換します．
`java.util.Calendar` | 変換元の時刻値を持つ`java.sql.Date`に変換します．
`Number` | 変換元の`long`値を時刻値として持つ`java.sql.Date`に変換します．
`String` | `DATE_PATTERN`フォーマットに従い`java.sql.Date`に変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.sql.Time` | `java.sql.Time` | -
`java.util.Date` | 変換元の時刻値を持つ`java.sql.Time`に変換します．
`java.util.Calendar` | 変換元の時刻値を持つ`java.sql.Time`に変換します．
`Number` | 変換元の`long`値を時刻値として持つ`java.sql.Time`に変換します．
`String` | `TIME_PATTERN`フォーマットに従い`java.sql.Time`に変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
`java.sql.Timestamp` | `java.sql.Timestamp` | -
`java.util.Date` | 変換元の時刻値を持つ`java.sql.Timestamp`に変換します．
`java.util.Calendar` | 変換元の時刻値を持つ`java.sql.Timestamp`に変換します．
`Number` | 変換元の`long`値を時刻値として持つ`java.sql.Timestamp`に変換します．
`String` | `TIMESTAMP_PATTERN`フォーマットに従い`java.sql.Timestamp`に変換します． 詳細は「日付・時刻のフォーマット」を参照してください．
配列 | 配列 | 変換元と同じ大きさの配列に変換します． 変換元配列の要素は変換先配列の要素型に変換します．
`java.util.Collection` | 変換元と同じ大きさの配列に変換します．変換元が順序のあるコレクション(`java.util.List`や`java.util.LinkedHashSet`など)の場合，順序は維持されます． 変換元の要素は変換先配列の要素型に変換します．
その他任意の型 | 変換元を変換先配列の要素型に変換したオブジェクトを唯一の要素とする配列に変換します．
`java.util.List` | `java.util.List` | -
配列 | 変換元と同じ大きさのリストに変換します． 変換元配列の要素はそのまま変換先リストの要素になります．
`java.util.Collection` | 変換元と同じ大きさのリストに変換します．変換元が順序のあるコレクション(`java.util.List`や`java.util.LinkedHashSet`など)の場合，順序は維持されます． 変換元コレクションの要素はそのまま変換先リストの要素になります．
その他任意の型 | 変換元を変換先配列の要素型に変換したオブジェクトを唯一の要素とするリストに変換します．
`java.util.Set` | `java.util.Set` | -
配列 | 変換元と同じ大きさのセット(`java.util.LinkedHashSet`)に変換します．配列の順序は維持されます． 変換元配列の要素はそのまま変換先セットの要素になります．
`java.util.Collection` | 変換元と同じ大きさのセット(`java.util.LinkedHashSet`)に変換します．変換元が順序のあるコレクション(`java.util.List`や`java.util.LinkedHashSet`など)の場合，順序は維持されます． 変換元コレクションの要素はそのまま変換先リストの要素になります．
その他任意の型 | 変換元を変換先配列の要素型に変換したオブジェクトを唯一の要素とするリストに変換します．
JavaBeans | JavaBeans | 変換元JavaBeansを変換先JavaBeansに変換します． 変換元JavaBeansのプロパティは変換先JavaBeansの対応するプロパティに変換されます．
`Number` | `Enum`のサブクラス | 変換元の数値を序数とする列挙定数に変換します (S2-Tigerが必要です)． 変換は`Class#getEnumConstants()`が返す配列を使って行われます．
その他任意の型 | 変換元の文字列表現を名前とする列挙定数に変換します (S2-Tigerが必要です)． 変換は`Enum#valueOf(Class, String)`で行われます．
### ネストしたJavaBeansのプロパティ 変換先のJavaBeansに存在するプロパティと同名のプロパティが変換元のJavaBeansに存在しない場合，S2DxoはネストしたJavaBeansのプロパティを探します．ネストしたJavaBeansのプロパティとは，変換元JavaBeansが持つJavaBeansを型とするプロパティのプロパティです．この探索は一段階のみ行われます．
    public class Employee {
        private Department department;
        ・・・
    }

    public class Department {
        private String dname;
        ・・・
    }

    public class EmployeePage {
        private String dname;
        ・・・
    }
上の例で，`Employee`から`EmployeePage`への変換を行うと，`EmployeePage`の`dname`プロパティには，`Employee`の`department`プロパティが参照する，`Department`の`dname`プロパティが設定されます． より深くネストしたプロパティを扱うには，「変換元プロパティ名の指定」を参照してください． ## 変換のカスタマイズ ### 変換元プロパティ名の指定 変換元JavaBeansまたはマップのプロパティ名と変換先JavaBeansまたはマップのプロパティ名が異なる場合はアノテーションで変換ルールを指定することができます．アノテーションはDXOのメソッドに定数アノテーションまたはTigerアノテーションで指定します． 変換ルールは文字列で，その内容は
    destPropertyName : sourcePropertyName
という組をカンマ区切りで並べたものです．変換先のプロパティ名が前になるので注意してください． 変換元のプロパティ名には，ネストしたJavaBeansのプロパティ名をピリオド区切りで指定することもできます．
    ename : name, dname : department.name
という変換ルールを指定した場合，変換先JavaBeansの`ename`プロパティには変換元JavaBeansの`name`プロパティの値が，変換先JavaBeansの`dname`プロパティには変換元JavaBeansの`department`プロパティに設定されているJavaBeansの`name`プロパティの値が設定されます．必要があれば「型変換」に従って変換が行われます．ただし，`department`が`null`だと変換先JavaBeansの`dname`プロパティには`null`が設定されます． JavaBeansからMapに変換する場合，変換ルールを指定すると指定したプロパティだけが変換先のマップに追加されることになるので注意してください． 変換元プロパティ名の代わりに`null`を指定することもできます。
    ename : name, dname : null
という変換ルールを指定した場合，変換先JavaBeansの`dname`プロパティには`null`が設定されます． #### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数として次のように指定します．定数名はメソッド名の後ろに`"_CONVERSION_RULE"`をつけたものになります．
    public interface FooDxo {
        String convert_CONVERSION_RULE = "ename : name, dname : department.name";
        EmployeePage convert(Employee employee);
    }
DXOインタフェースがメソッドをオーバーロードしている場合は，引数型の非修飾名をアンダースコア区切りで並べて指定することもできます．引数型が配列型の場合は配列要素の型名の後ろに'$'を付加します．'$'は配列の次元と同じ数だけ並べます．
    public interface BarDxo {
        String convert_Employee_CONVERSION_RULE = "ename : name";
        EmployeePage convert(Employee employee);

        String convert_Employee$_CONVERSION_RULE = "ename : name, dname : department.name";
        EmployeePage[] convert(Employee[] employees);

        DepartmentPage convert(Department department);
    }
この場合，最初の変換ルールは`convert(Employee)`メソッドにのみ適用され，2番目の変換ルールはconvert(Employee[])メソッドにのみ適用されます．`convert(Department)`メソッドにはどちらの変換ルールも適用されません． 引数型の指定されない変換ルールは，同じ名前のメソッド全てに適用されます．引数型を伴う変換ルールと引数型のない変換ルールが混在する場合は，引数型の一致する変換ルールのあるメソッドはその変換ルールが，引数型の一致する変換ルールがないメソッドは引数型を伴わない変換ルールが適用されます． #### Tigerアノテーション Tigerアノテーションでは，DXOメソッドのアノテーションとして次のように指定します．
    import org.seasar.extension.dxo.annotation.ConversionRule;
    pubic interface BazDxo {
        @ConversionRule("ename : name, dname : department.name")
        EmployeePage convert(Employee employee);
    }
### OGNL式の利用 前述の変換ルールでは，OGNL式の評価結果を変換先JavaBeansのプロパティに設定することもできます． この場合の変換ルールも文字列で，その内容は
    'destPropertyName' : expression
という組をカンマ区切りで並べたものです．変換先のプロパティ名はシングルクオートで囲んでください． OGNL式を利用する場合の変換ルールと「変換元プロパティ名の指定」のルールを混在することはできません．OGNL式を使用する場合は，ルール全体で変換先のプロパティ名をシングルクオートで囲む必要があります．
    'name' : ename + '-' + dname
という変換ルールを指定した場合，変換先JavaBeansの`name`プロパティには変換元JavaBeansの`ename`プロパティと`dname`プロパティをハイフン区切りで連結した値が設定されます．OGNLE式の評価結果が変換先JavaBeansのプロパティ型と異なる場合は「型変換」に従って変換が行われます． また，「変換元プロパティ名の指定」の次の例
    dname : department.name
この例で変換元の`department`が`null`だった場合は変換時に`NullPointerException`が発生してしまいます．`department`が`null`の場合は変換先の`dname`に`null`を設定するには、以下のようにOGNL式の3項演算子を使用してください．
    'dname' : department != null ? department.name : null
OGNL式の詳細については「OGNLガイド」を参照してください． #### 定数アノテーション 「変換元プロパティ名の指定」と同様に指定します．
    public interface FooDxo {
        String convert_CONVERSION_RULE = "'name' : ename + '-' + dname";
        EmployeePage convert(Employee employee);
    }
#### Tigerアノテーション 「変換元プロパティ名の指定」と同様に指定します．
    import org.seasar.extension.dxo.annotation.ConversionRule;
    public interface FooDxo {
        @ConversionRule("'name' : ename + '-' + dname")
        EmployeePage convert(Employee employee);
    }
### `null`のプロパティを変換から除外する 変換元JavaBeansのプロパティまたは`Map`のマッピングの値が`null`の場合は，変換先のJavaBeansまたは`Map`に値を設定しないことをアノテーションで指定することができます．アノテーションはDXOのメソッドに定数アノテーションまたはTigerアノテーションで指定します． #### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数として次のように指定します．定数名はメソッド名の後ろに`"_EXCLUDE_NULL"`をつけたものになります．
    public interface FooDxo {
        String convert_EXCLUDE_NULL = null;
        EmployeePage convert(Employee employee);
    }
DXOインタフェースがメソッドをオーバーロードしている場合は，「変換元プロパティ名の指定」と同様に，引数型の非修飾名をアンダースコア区切りで並べて指定することもできます． #### Tigerアノテーション Tigerアノテーションでは，DXOメソッドのアノテーションとして次のように指定します．
    import org.seasar.extension.dxo.annotation.ExcludeNull;
    pubic interface BazDxo {
        @ExcludeNull
        EmployeePage convert(Employee employee);
    }
### 空白文字列のプロパティを変換から除外する 変換元JavaBeansのプロパティまたは`Map`のマッピングの値が空白(スペース，タブ，復帰，改行)のみの文字列の場合は，変換先のJavaBeansまたは`Map`に値を設定しないことをアノテーションで指定することができます．アノテーションはDXOのメソッドに定数アノテーションまたはTigerアノテーションで指定します． #### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数として次のように指定します．定数名はメソッド名の後ろに`"_EXCLUDE_WHITESPACE"`をつけたものになります．
    public interface FooDxo {
        String convert_EXCLUDE_WHITESPACE = null;
        EmployeePage convert(Employee employee);
    }
DXOインタフェースがメソッドをオーバーロードしている場合は，「変換元プロパティ名の指定」と同様に，引数型の非修飾名をアンダースコア区切りで並べて指定することもできます． #### Tigerアノテーション Tigerアノテーションでは，DXOメソッドのアノテーションとして次のように指定します．
    import org.seasar.extension.dxo.annotation.ExcludeWhitespace;
    pubic interface BazDxo {
        @ExcludeSpace
        EmployeePage convert(Employee employee);
    }
### プレフィックス付きのプロパティ 変換元のJavaBeansまたは`Map`からプレフィックスの付いたプロパティまたはキーのみを変換変換対象としたり，変換元のプロパティ名にプレフィックスを付けて変換対象としたりすることができます．プレフィックスはDXOのメソッドに定数アノテーションまたはTigerアノテーションで指定します． #### ソースプレフィックス ソースプレフィックスが指定されると，変換元JavaBeansのプロパティまたはMapのキーの中で，ソースプレフィックスで始まる物だけが変換の対象となります．変換先のJavaBeansまたはMapへはソースプレフィックスを取り除いたプロパティまたはキーで設定されます． 変換元として次のようなクラスがあるとします．
    public class SearchPage {
        private String search_name_GE;
        private String search_name_LE;
        private String search_name_STARTS;
        private String search_name_ENDS;
        ...
    }
変換先は次のようなクラスです．
    public clsss EmpDto {
        private String name_GE;
        private String name_LE;
        private String name_STARTS;
        private String name_ENDS;
        ...
    }
このような場合に，'`search_`'で始まるプロパティだけを対象として，変換先の'`search_`'を取り除いた名前のプロパティに設定することができます． ##### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数として次のように指定します．定数名はメソッド名の後ろに`"_SOURCE_PREFIX"`をつけたものになります．
    public interface FooDxo {
        String convert_SOURCE_PREFIX = "search_";
        EmpDto convert(SearchPage page);
    }
DXOインタフェースがメソッドをオーバーロードしている場合は，「変換元プロパティ名の指定」と同様に，引数型の非修飾名をアンダースコア区切りで並べて指定することもできます．引数型が配列型の場合は配列要素の型名の後ろに'$'を付加します．'$'は配列の次元と同じ数だけ並べます． ##### Tigerアノテーション Tigerアノテーションでは，DXOメソッドのアノテーションとして次のように指定します．
    import org.seasar.extension.dxo.annotation.SourcePrefix;
    public interface BarDxo {
        @SourcePrefix("search_")
        EmpDto convert(SearchPage page);
    }
#### デスティネーションプレフィックス デスティネーションプレフィックスが指定されると，変換元JavaBeansのプロパティまたはMapのキーに，デスティネーションプレフィックス付加した名前がで変換先のJavaBeansまたはMapに設定されます． 変換元として次のようなクラスがあるとします．
    public clsss EmpDto {
        private String name_GE;
        private String name_LE;
        private String name_STARTS;
        private String name_ENDS;
        ...
    }
変換先は次のようなクラスです．
    public class SearchPage {
        private String search_name_GE;
        private String search_name_LE;
        private String search_name_STARTS;
        private String search_name_ENDS;
        ...
    }
このような場合に，変換元のプロパティに'`search_`'を付加した名前の変換先プロパティに設定することができます． ##### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数として次のように指定します．定数名はメソッド名の後ろに`"_DEST_PREFIX"`をつけたものになります．
    public interface FooDxo {
        String convert_DEST_PREFIX = "search_";
        void convert(EmpEto src, SearchPage dest);
    }
DXOインタフェースがメソッドをオーバーロードしている場合は，「変換元プロパティ名の指定」と同様に，引数型の非修飾名をアンダースコア区切りで並べて指定することもできます．引数型が配列型の場合は配列要素の型名の後ろに'$'を付加します．'$'は配列の次元と同じ数だけ並べます． ##### Tigerアノテーション Tigerアノテーションでは，DXOメソッドのアノテーションとして次のように指定します．
    import org.seasar.extension.dxo.annotation.SourcePrefix;
    public interface BarDxo {
        @SourcePrefix("search_")
        void convert(EmpDto src, SearchPage dest);
    }
### 日付・時刻のフォーマット `java.util.Date`や`java.util.Calendar`などと`String`との相互変換を行う場合には，フォーマットパターンを指定することができます．フォーマットパターンは`java.text.SimpleDateFormat`が解釈することができるパターン文字列で，DXOインタフェースまたはそのメソッドにアノテーションで指定することができます．アノテーションが指定されたメソッドで行われる変換の際に，JavaBeansのプロパティに`java.util.Date`や`java.util.Calendar`などと`String`との変換が必要になると，指定されたフォーマットパターンが使われます．フォーマットパターンが指定されなかった場合は，デフォルトロケールのデフォルトパターンが使われます． #### 定数アノテーション 定数アノテーションでは，DXOインタフェースの文字列定数としてフォーマットパターンを指定します．定数名は次のいずれかで，最初に見つかったものが適用されます． `methodName[_parameterType ...]_patternName` 指定された名前と引数並びを持つメソッドに固有のフォーマットパターンを指定します． `methodName_patternName` 指定された名前を持つメソッドに固有のフォーマットパターンを指定します． `patternName` DXOインタフェース内の全メソッドに適用されるフォーマットパターンを指定します． `patternName`は次のいずれかです．
パターン名 | 適用される型
--- | ---
`DATE_PATTERN` | `java.util.Calendar`
`java.util.Date`
`java.sql.Date`
`TIME_PATTERN` | `java.sql.Time`
`TIMESTAMP_PATTERN` | `java.sql.Timestamp`
次のようになります．
    public interface FooDxo {
        String DATE_PATTERN = "yyyy-MM-dd";
        String TIME_PATTERN = "HH:mm:ss.SSS";
        String TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss";

        String convert_DATE_PATTERN = "yyyy/MM/dd";
        String convert_Foo_TIME_PATTERN = "HH:mm:ss";
        String convert2_TIMESTAMP_PATTERN = "yyyy/MM/dd HH:mm:ss.SSS";

        Bar convert(Foo foo);
        Foo convert(Bar bar);
        Bar convert2(Foo foo);
    }
上の例では，次の表のように定数アノテーションが適用されます．
メソッド | `DATE_PATTERN` | `TIME_PATTERN` | `TIMESTAMP_PATTERN`
--- | --- | --- | ---
`convert(Foo)` | `convert_DATE_PATTERN` | `convert_Foo_TIME_PATTERN` | `TIMESTAMP_PATTERN`
`convert(Bar)` | `convert_DATE_PATTERN` | `TIME_PATTERN` | `TIMESTAMP_PATTERN`
`convert2(Foo)` | `DATE_PATTERN` | `TIME_PATTERN` | `TIMESTAMP_PATTERN`
#### Tigerアノテーション Tigerアノテーションでは，DXOのメソッドまたはインタフェースのアノテーションとして指定します．
アノテーション | 適用される型
--- | ---
`org.seasar.extension.dxo.DatePattern` | `java.util.Calendar`
`java.util.Date`
`java.sql.Date`
`org.seasar.extension.dxo.TimePattern` | `java.sql.Time`
`org.seasar.extension.dxo.TimestampPattern` | `java.sql.Timestamp`
次のようになります．
    @DatePattern("yyyy-MM-dd")
    @TimePattern("HH:mm:ss.SSS")
    @TimestampPattern("yyyy-MM-dd HH:mm:ss")
    public interface FooDxo {
        @DatePattern("yyyy/MM/dd")
        @TimePattern("HH:mm:ss")
        Bar convert(Foo foo);

        @DatePattern("yyyy/MM/dd")
        Foo convert(Bar bar);

        @TimestampPattern("yyyy/MM/dd HH:mm:ss.SSS")
        Bar convert2(Foo foo);
    }
上の例では，定数アノテーションの例と同じになるようにフォーマットパターンを指定しています． ### 独自のコンバータ プロパティやマップの要素の型が異なる場合はコンバータによって型変換されます．独自のコンバータを作成することにより，「型変換」に記述されていない独自の型をサポートすることができます． #### コンバータの作成 コンバータは`org.seasar.extension.dxo.converter.Converter`インタフェースを実装したクラスで，次のメソッドを持ちます． `Class[] getSourceClasses()` このコンバータがサポートしている変換元のクラスを配列で返します． `Class getDestClass()` このコンバータがサポートしている変換先のクラスを返します `Object convert(Object source, Class destClass, ConversionContext context)` `source`を`destClass`のインスタンスに変換して返します． `void convert(Object source, Object dest, ConversionContext context)` `source`を`dist`に変換します．不変なオブジェクトへの変換を行うコンバータはこのメソッドを実装できないため，このメソッドが呼び出されると`UnsupportedOperationException`をスローします． コンバータのクラス名は"`DxoConverter`"で終了するようにします． 以下は文字列 (`String`) を正規表現 (`java.util.regex.Pattern`) に変換するコンバータの例です．
    public class PatternDxoConverter implements Converter {

        public Class[] getSourceClasses() {
            return new Class[] { String.class };
        }

        public Class getDestClass() {
            return Pattern.class;
        }

        public Object convert(Object source, Class destClass,
                ConversionContext context) {
            return Pattern.compile((String) source);
        }

        public void convert(Object source, Object dest, ConversionContext context) {
            throw new UnsupportedOperationException();
        }

    }
独自作成したコンバータはdiconファイルに定義するか，AutoRegisterによりS2コンテナに自動登録されるようにします． #### diconファイルへの登録 独自作成したコンバータは，diconファイルに登録して使用します．コンバータのコンポーネント名は"`DxoConverter`"で終了するようにします．
    <?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 name="patternDxoConverter" instance="prototype"
        class="org.seasar.extension.dxo.annotation.impl.ConstantAnnotationReaderTest$HogeDxoConverter"/>
    </components>
AutoRegisterを使って自動登録することもできます．コンポーネントとして登録されたコンバータはS2Dxoに組み込まれ，「型変換」に記述されている標準のコンバータと同じように動作します． 「型変換」に記述されている標準のコンバータは，`dxo-builtin-converters.dicon`および`dxo-tiger-converters.dicon`に定義されています．これらのdiconファイルは，それぞれ`s2-extension-2.4.x.jar`および`s2-tiger-2.4.x.jar`の中にバンドルされています．標準のコンバータを独自作成したコンバータに変更する場合はこれらのdiconファイルを置き換えてください． #### アノテーションでコンバータを明示する 変換先JavaBeansのプロパティに特定のコンバータを使用することを明示することもできます． 定数アノテーションでは，変換先クラスに文字列定数として次のように指定します．定数名は，コンバータを適用するプロパティ名の後ろに`"_コンバータ名"`をつけたものになります．コンバータ名は独自作成したコンバータのコンポーネント名で，最後は"`DxoConverter`"で終了しなければなりません．
    public class Dest {
      // namePattern プロパティは PatternDxoConverter を使って変換
      public static final namePattern_patternDxoConverter = null;
      private Pattern namePattern;
      ...
      public void setNamePattern(Pattern namePattern) {
        this.namePattern = namePattern;
      }
    }
独自作成したコンバータにプロパティがあれば設定することもできます．
      public static final name_prefixDxoConverter = "prefix='$$'";
Tigerアノテーションの場合は，独自コンバータのためのアノテーションを作成します．
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @DxoConverter("patternDxoConverter")
    public @interface PatternDxoConverter {
    }
変換先クラスのsetterメソッドまたはpublicフィールドに作成したアノテーションを次のように指定します．
    public class Dest {
      private Pattern namePattern;
      ...
      @PatternDxoConverter
      public void setNamePattern(Pattern namePattern) {
        this.namePattern = namePattern;
      }
    }
独自作成したコンバータにプロパティがある場合は，アノテーションにプロパティのための要素を持たせます．
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @DxoConverter("prefixDxoConverter")
    public @interface PrefixDxoConverter {
        String prefix();
    }
変換先クラスのsetterメソッドに作成したアノテーションを次のように指定します．
      @PrefixDxoConverter(prefix="$$")
      public void setName(String name) {
        this.name = name;
      }
### シャローコピー Seasar2.4.17以前は，変換元と変換先が同じクラスの場合は，変換元のインスタンスをそのまま変換先として使用していました (シャローコピー的) が， 2.4.18からは，新しいインスタンスを作成するようになりました (ディープコピー的)． 2.4.17以前とと同様の振る舞い (シャローコピー的) が必要な場合は，`dxo.dicon` でインクルードする `dxo-builtin-converters.dicon` を，`dxo-builtin-converters-shallow.dicon` に差し替えて使用してください． dicon の差し替えは，`s2container.dicon` の中で次のように指定します．
    <component class="org.seasar.framework.container.factory.SimplePathResolver">
      <initMethod name="addRealPath">
        <arg>"dxo-builtin-converters.dicon"</arg>
        <arg>"dxo-builtin-converters-shallow.dicon"</arg>
      </initMethod>
    </component>
| Copyright© 2004-2005, The Seasar Foundation and the others. All rights reserved.