ドメインクラスで型パラメータをサポート
twitter:@backpaper0
さんの発言から。
いいですね!
さっそく実装してSNAPSHOTつくってみました。
ぜひお試しください。ブラッシュアップして次のバージョン(1.32.0)で正式リリースに組み込みたいと考えています。
使用例
使用例を示します。
以下のようにドメインクラスに任意の数の型パラメータを指定できます。ここでは1個だけですが、何個でもOK。
@Domain(valueType = int.class) public class Weight<T> { private final int value; public Weight(int value) { this.value = value; } public int getValue() { return value; } public Weight<T> add(Weight<T> other) { return new Weight<T>(value + other.value); } }
利用する側では次のように実型引数に具体的な型を指定します(ワイルドカードや型変数の使用はサポートしていません)。
@Entity public class Person { public Weight<kg> weight; }
@Entity public class Food { public Weight<g> weight; }
上の例では、単位を表すkgやgという型を作って型引数にしました。
public interface kg {}
public interface g {}
これでいったい何がうれしいかというと、Weight
つまり、次のようなコードはコンパイルできません。
Person person = ... Food food = ... Weight<kg> weight = person.weight.add(food.weight);
Domainでファクトリメソッドを使うには ?
上の使用例では、Domainクラスをコンストラクタでインスタンス化しています。
ファクトリメソッドが好きな人もいるでしょう。
ファクトリメソッドでは、クラスの型変数宣言と同等の宣言をしてください。
この例では、ofメソッドがファクトリメソッドです。
@Domain(valueType = int.class, factoryMethod = "of") public class Weight<T> { private final int value; private Weight(int value) { this.value = value; } public int getValue() { return value; } public Weight<T> add(Weight<T> other) { return new Weight<T>(value + other.value); } public static <T> Weight<T> of(int value) { return new Weight<T>(value); } }
ExternalDomainを使うには ?
ValueObjectにアノテーションをつけたくない(つけられない)場合のために、ExternalDomainという機能がありますが、こちらでも型パラメータに対応しています。
注意点は1つです。
- DomainConverterの実装では、Domainクラスはワイルドカードを使って扱ってください。
これがValueObject。上の例と違ってアノテーションついていません。
public class Weight<T> { private final int value; public Weight(int value) { this.value = value; } public int getValue() { return value; } public Weight<T> add(Weight<T> other) { return new Weight<T>(value + other.value); } }
これが、ValueObjectと基本的な値を相互変換するコンバーター(DomainConverterの実装)。Weightの型引数に?(ワイルドカード)を指定しています。
@ExternalDomain public class WeightConverter implements DomainConverter<Weight<?>, Integer> { @Override public Integer fromDomainToValue(Weight<?> domain) { ... } @Override public Weight<?> fromValueToDomain(Integer value) { ... } }