DXO (Data eXchange Object) とは,PONO(Plain Old NET Object)とPONO、PONOとCollection、PONOとDictionaryを相互変換 (exchange)することを目的としたオブジェクトです.主な用途としては,プレゼンテーション層のモデル (ページ) とドメイン層のモデル (エンティティ) を相互変換することを意図しています.
S2DxoはDXOを実現するためのフレームワークです.S2Dxoを使うと,インタフェースを定義するだけで DXOを実現することが可能となります.
さっそく試してみましょう.登場人物はC#の場合、次のようになります.
変換元のPONO
EmployeeとDepartmentの二つ.EmployeeはDepartmentを参照します.
変換先のPONO
EmployeePage.EmployeePageはEmployeeとDepartmentの両方のプロパティを持っています.
変換を行うDXO
EmployeeDxo.EmployeeとDepartmentをEmployeePageに変換するDXOのインタフェースです.
S2Dxoは,上記3つのPONOに対して,以下の図のような変換を行います.
変換元のPONOです.Departmentを参照します.
namespace Seasar.Tests.Dxo { public class Employee { private Department _department; private string _ename; public string EName { get { return _ename; } set { _ename = value; } } public Department Department { get { return _department; } set { _department = value; } } } }
変換元のPONOです.Employeeから参照されます.
namespace Seasar.Tests.Dxo { public class Department { private string _dname; public string DName { get { return _dname; } set { _dname = value; } } } }
変換先のPONOです.EmployeeのプロパティENameに加えて,DepartmentのプロパティDepartmentも 持っています.
namespace Seasar.Tests.Dxo { public class EmployeePage { private string _dname; private string _ename; public string Department { get { return _dname; } set { _dname = value; } } public string EName { get { return _ename; } set { _ename = value; } } } }
変換を行うDXOです.引数として変換元のPONOであるEmployeeを受け取り,戻り値として 変換先のPONOであるEmployeePageを返します.単なるインタフェースで実装がないことに 注目してください.
また、逆にEmployeePageからEmployeeへの変換も出来ます
namespace Seasar.Tests.Dxo { public interface IEmployeeDxo { EmployeePage ConvertToEmployeePage(Employee emp); void ConvertPageToEmp(EmployeePage page, Employee emp); } }
EmployeeDxoを利用するために必要な設定を記述します.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components namespace="dxo"> <!-- インターセプタ --> <component name="interceptor" class="Seasar.Dxo.Interceptor.DxoInterceptor"/> <!-- コンポーネント --> <component class="Seasar.Tests.Dxo.IEmployeeDxo"> <aspect pointcut="*">interceptor</aspect> </component> </components>
実行クラスの中では次のように記述します.
[Test, S2] public void TestSimple() { Include(PATH); IEmployeeDxo dxo = (IEmployeeDxo) GetComponent(typeof (IEmployeeDxo)); Employee employee = new Employee(); employee.EName = "Mike"; Department dept = new Department(); dept.Department = "Sales"; employee.Department = dept; EmployeePage page = dxo.ConvertToEmployeePage(employee); Assert.AreEqual("Mike", page.EName, "EName"); Assert.AreEqual("Sales", page.Department, "Department"); if (!String.IsNullOrEmpty(page.Name)) Assert.Fail("Name2"); }
Dxoは通常インターフェイスとして定義します。
次のようになります。
C#
public interface IFooDxo { ... }
VB
Public Interface IFooDxo ... End Interface
Dxoには変換を行うメソッドを定義します。メソッド名は自由に定義できますが、 慣例的にConvertで始めます。
DXOのメソッドは次の2つの形式のいずれかにすることができます。
戻り値が変換後型の場合はS2Dxo.NETがインスタンスを生成して返します。 戻り値がvoidの場合は第2引数で受け取ったインスタンスを更新します。
変換前及び変換後の型の組み合わせは次のものがサポートされています。
変換前型 | 変換後型 |
---|---|
PONO | PONO |
PONO[] | PONO[] |
PONO | System.Collections.Generic.IList<PONO> |
System.Collections.Generic.IList<PONO> | System.Collections.Generic.IList<PONO> |
PONO | System.Collections.IDictionary |
System.Collections.IDictionary | PONO |
例えば次のようになります。
C#
public interface IFooDxo { void ConvertPonoToPono(FromBean fromBean, ToBean toBean); ToBean ConvertToPono(FromBean fromBean); void ConvertFromArrayToArray(FromBean[] fromArray, ToBean[]toArray); ToBean[] ConvertToArray(FromBean[] fromArray); void ConvertListToList(IList<FromBean> fromArray, IList<ToBean> toArray); List<ToBean> ConvertToList(IList<FromBean> toArray); void ConvertToDictinary(FromBean emp, IDictionary dict); void ConvertFromDictionaryToPONO(IDictionary dict, FromBean emp); }
DXOインタフェースにはS2Dxo.NETの提供するインターセプタを適用します
<components namespace="dxo"> <!-- インターセプタ --> <component name="interceptor" class="Seasar.Dxo.Interceptor.DxoInterceptor"/> </components>
PONOまたはIDictionaryからPONOに変換する場合,変換先となるPONOのプロパティを変換元から探し, (必要なら)型変換を行って変換先のプロパティに設定します.
PONOからIDicitionaryに変換する場合は,変換元のPONOの全プロパティについて変換先の IDictionaryに追加します.追加されるエントリのキーは変換元のプロパティ名(string),値は変換元のプロパティ値です.
変換元と変換先の型が異なる場合は型変換が行われます.S2Dxoが標準で提供する型変換は以下の通りです.変換先の型を基準に参照してください.
変換元の型 | 変換先の型 | 説明 |
---|---|---|
bool | bool | - |
short, int, long | 1以上であればtrue, それ以外はfalseに変換. | |
その他任意の型 | 変換元を文字列化し、それが"yes", "y", "true", "on", "1"の いずれかならばtrue, そうでなければfalseに変換 | |
bool | short, int, long | 変換元がtrueなら1,そうでなければ0に変換. |
short, int, long | 同等の値に変換します. | |
string | 文字列の表現する数値と同等の値に変換します. | |
char | char | - |
string | string | - |
char[] | 変換元を文字シーケンスとして持つstringに変換します. | |
System.DataTime | DatePattern属性に従い変換します. 詳細は「日付・時刻のフォーマット」を参照してください. | |
char[] | char[] | - |
string | 変換元の持つ文字配列に変換します. | |
System.DateTime | System.DateTime | - |
long | 変換元のlong値を時刻値として持つSystem.DateTimeに変換します. | |
string | DatePattern属性に従いSystem.DateTimeに変換します. 詳細は「日付・時刻のフォーマット」を参照してください. | |
PONO | PONO | 変換元PONOを変換先PONOに変換します. 変換元PONOのプロパティは変換先PONOの対応するプロパティに変換されます. |
変換先のPONOに存在するプロパティと同名のプロパティが変換元のPONOに存在しない場合, S2DxoはネストしたPONOのプロパティを探します.ネストしたPONOのプロパティとは, 変換元PONOが持つPONOを型とするプロパティのプロパティです.
この探索はJava版と同様に一段階のみ行われます.
C#
public class Employee { private Department _department; public Department Dept { get { return _department; } set { _department = value; } } ... } public class Department { private string _dname; public string DName { get { return _dname; } set { _dname = value; } } ... } public class EmployeePage { private string _dname; public string DName { get { return _dname; } set { _dname = value; } } ... }
上の例で,EmployeeからEmployeePageへの変換を行うと,EmployeePageのDNameプロパティには, EmployeeのDeptプロパティが参照する,DepartmentのDNameプロパティが設定されます.
変換元PONOまたはマップのプロパティ名と変換先PONOまたはマップのプロパティ名が 異なる場合は属性で変換ルールを指定することができます.
変換元のプロパティと変換先のプロパティをSeasar.Dxo.Annotation.ConversionRuleAttributeで指定します.
例えば次のようになります。
C#
public interface IFooDxo { [ConversionRule(PropertyName = "EName", TargetPropertyName = "DName")] [ConversionRule("DName","EName")] ToBean ConvertBeanToTarget(FromBean source); }
VB
Public Interface IFooDxo <ConversionRule(PropertyName = "EName", TargetPropertyName = "DName")> _ <ConversionRule("DName","EName")> _ Function ConvertBeanToTarget(ByVal source As FromBean) As ToBean End Interface
System.DateTimeとstringとの相互変換を行う場合にはフォーマットパターンを指定できます.
フォーマットパターンは解釈することができるパターン文字列で,DXOインタフェースのメソッドにSeasar.Dxo.Annotation.DatePatternAttributeで指定することができます.属性が指定されたメソッドで行われる変換の際に,PONOのプロパティにSystem.DateTimeとstringとの変換が必要になると,指定されたフォーマットパターンが使われます.フォーマットパターンが指定されなかった場合は,デフォルトロケールのデフォルトパターンが使われます.
例えば次のようになります。
C#
public interface IFooDxo { [DatePattern("yyyyMMdd")] ToBean ConvertBeanToTarget(FromBean source); }
VB
Public Interface IFooDxo <DatePattern("yyyyMMdd")> _ Function ConvertBeanToTarget(ByVal source As FromBean) As ToBean End Interface
Seasar.NET 1.4.0, 1.3.19以降では、DxoInterceptorをスレッドセーフにする対応のため、下記プロパティ、メソッドが変更になっています。
Seasar.Dxo.Interceptor.DxoInterceptorを拡張してご利用している場合はご注意下さい。