概要
Domain(ドメイン)クラスの定義方法を示します。 ドメインとは、値のとり得る範囲(定義域)のことです。 Domaでは、テーブルのカラムの値を、ドメインと呼ばれるJavaオブジェクトで扱います。
ドメインクラスを利用することで、データベース上のカラムの型が同じあってもアプリケーション上意味が異なるものを別のJavaの型で表現できます。 これにより、意味を明確にしプログラミングミスを事前に防ぎやすくなります。 また、ドメインクラスに振る舞いを持たせることで、よりわかりやすいプログラミングが可能です。
ドメインクラスの作成と利用は任意です。
ドメインクラスを利用しなくてもIntegerやStringなど基本型のみでデータアクセスは可能です。
ドメイン定義
ドメインクラスは @Domainを注釈して示します。
@DomainのvalueType要素には、ドメインクラスで扱う基本型を指定します。この基本型が、データベースのカラムの型とのマッピングに使用されます。
accessorMethod要素には、valueType要素に指定した型を返すアクセッサメソッドの名前を指定します。デフォルト値は"getValue"です。
factoryMethod要素には、valueType要素に指定した型をパラメータとし受け取りドメインクラスの型を返すファクトリメソッドの名前を指定します。デフォルト値は"new"であり、これはコンストラクタにより生成することを示します。
@Domainが注釈されたクラスは以下の制約を満たす必要があります。
- トップレベルのクラスまたは列挙型である。
valueType要素に指定した型を引数とする非privateなコンストラクタを持ち、factoryMethod要素が"new"である。もしくは、factoryMethod要素に指定した名前のstaticで非privateなメソッドを持ち、戻り値は注釈された型であり、 パラメータはvalueType要素に指定した型である。accessorMethod要素に指定した名前の非privateなメソッドを持つ。このメソッドは、valueType要素に指定した型を戻り値とし、パラメータは受け取らない。
任意ですが、ドメインクラスは不変オブジェクトとして作成することを推奨します。 クラスには、任意のメソッドを持たせることができます。
列挙型は非privateなコンストラクタを定義できないため、列挙型に対してはファクトリメソッドを用いた方法を使用する必要があります。
コンストラクタで生成する
@DomainのfactoryMethod要素のデフォルトの値はnewであり、
非privateなコンストラクタでインスタンスを生成することを示します。そのため、コンストラクタで生成する場合はfactoryMethod要素を省略できます。
次の例では、 publicなコンストラクタを持つドメインクラスを作成しています。 このクラスは電話番号を表しています。
package example.domain;
import org.seasar.doma.Domain;
@Domain(valueType = String.class)
public class PhoneNumber {
private final String value;
public PhoneNumber(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String getAreaCode() {
// ドメインに固有の振る舞いを記述できる。
...
}
}
ファクトリメソッドで生成する
コンストラクタをprivateにし、ファクトリメソッドを使ってインスタンスを生成したい場合は、
staticな非privateなメソッドを定義し@DomainのfactoryMethod要素にそのメソッドの名前を指定します。
次の例では、publicな ファクトリメソッドをもつドメインクラスを作成しています。 このクラスは電話番号を表しています。
package example.domain;
import org.seasar.doma.Domain;
@Domain(valueType = String.class, factoryMethod = "of")
public class PhoneNumber {
private final String value;
private PhoneNumber(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String getAreaCode() {
// ドメインに固有の振る舞いを記述できる。
...
}
public static PhoneNumber of(String value) {
return new PhoneNumber(value);
}
}
次の例では、publicな ファクトリメソッドをもつ列挙型をドメインクラスとして作成しています。 この列挙型は仕事の種別を表しています。
package example.domain;
import org.seasar.doma.Domain;
@Domain(valueType = String.class, factoryMethod = "of")
public enum JobType {
SALESMAN("10"),
MANAGER("20"),
ANALYST("30"),
PRESIDENT("40"),
CLERK("50");
private final String value;
private JobType(String value) {
this.value = value;
}
public static JobType of(String value) {
for (JobType jobType : JobType.values()) {
if (jobType.value.equals(value)) {
return jobType;
}
}
throw new IllegalArgumentException(value);
}
public String getValue() {
return value;
}
}
利用例
エンティティクラス
エンティティクラスのフィールドの型での利用例です。
@Entity
public class Employee {
@Id
Integer employeeId;
String employeeName;
PhoneNumber phoneNumber;
JobType jobType;
@Version
Integer versionNo();
...
}
Daoインタフェース
Daoインタフェースのメソッドのパラメータや戻り値での利用例です。
@Dao(config = AppConfig.class)
public interface EmployeeDao {
@Select
Employee selectByPhoneNumber(PhoneNumber phoneNumber);
@Select
List<PhoneNumber> selectAllPhoneNumber();
@Select
Employee selectByJobType(JobType jobType);
@Select
List<JobType> selectAllJobTypes();
}
