EXPERIMENTALな位置づけです。
https://www.seasar.org/issues/browse/DOMA-297
http://www.seasar.org/wiki/index.php?SeasarWhatsNew%2F2013-09-19#s71b7bbb
@Entity
のimmutable
要素にtrue
を指定してイミュータブルであることを示せます。
ポイントは以下の通りです。
- 永続フィールドにはfinal修飾子が必要
- コンストラクタのパラメータの型と名前は永続対象フィールドと一致しなければいけない
@OriginalStates
との併用はできない
@Entity(listener = EmpListener.class, immutable = true)
@Table(name = "EMPLOYEE")
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequence = "EMPLOYEE_SEQ")
final Integer id;
final String name;
final int age;
public Emp(Integer id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
...
}
EntityListenerの中で新しいエンティティを生成し後続処理に反映させたい場合は、context.setNewEntity(newEmp)
を呼びます。
public class EmpListener implements EntityListener<Emp> {
@Override
public void preInsert(Emp emp, PreInsertContext context) {
Emp newEmp = new Emp(...);
context.setNewEntity(newEmp);
}
...
}
イミュータブルなエンティティを更新系のメソッドに渡す場合のポイントは次の通りです。
@Insert
/@Update
/@Delete
を注釈したメソッドの戻り値はorg.seasar.doma.jdbc.Result
@BatchInsert
/@BatchUpdate
/@BatchDelete
を注釈したメソッドの戻り値はorg.seasar.doma.jdbc.BatchResult
@Dao(config = AppConfig.class)
public interface EmpDao {
@Insert
Result<Emp> insert(Emp emp);
@Update
Result<Emp> update(Emp emp);
@Delete
Result<Emp> delete(Emp emp);
@BatchInsert
BatchResult<Emp> insert(List<Emp> emp);
@BatchUpdate
BatchResult<Emp> update(List<Emp> emp);
@BatchDelete
BatchResult<Emp> delete(List<Emp> emp);
}
エンティティにlombokの@Value
を注釈して動作することを確認しています(Eclipseで確認)。
@Entity(listener = EmpListener.class, immutable = true)
@Table(name = "EMPLOYEE")
@Value
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequence = "EMPLOYEE_SEQ")
Integer id;
String name;
int age;
}
javacで実行すると、lombokとDomaのannotation processorの処理順序の問題で、上記のコードではうまく動きません。lombokの処理が先に動作することを期待しているからです。annotation processorでは処理順序を制御できません。
回避策として、次の2点を行ってください。
- プロパティにfinalをつける
- コンストラクタを作成する
この回避策により、lombokとDomaのannotation processorに依存関係がなくなります。