はじめに(と原因)
Play FrameworkとEbeanを使用している環境で、エンティティに対して、
setterを宣言しているインターフェースを実装するように修正したら、
意図しない動きになった。
原因は下記記事に記載されている。
Play Framework のエンハンス
(中略)
エンティティに対して、getterとsetterがついていないものはそれをつけるようにします。
その後で、エンティティのフィールド直接アクセスを、getter/setter経由になるように書き換えます。Ebean の エンハンス
(中略)
遅延ローディングや楽観的ロックの制御等の目的で、getterやsetterソースコードが改変されます。
Lombokを疑っていたが、Play FrameworkとEbeanでエンハンスしているとは...
修正前のコード
- エンティティ
@Entity
@Table(name = "HOGE")
public class Hoge extends Model {
public String field1;
public String field2;
@Override
public void save() {
super.save();
}
}
- 呼び出し元
public void execute() {
Hoge hoge = new Hoge();
hoge.field1 = "aaa";
hoge.field2 = "bbb";
hoge.save();
}
インターフェースを実装しようと思った理由
Hogeと同一項目を持つFugaが存在しており、Fugaに対しても更新することになった。
しかし、呼び出し元で似たような処理を書きたくなく、インターフェースにして
処理は1つにしたかったため。
修正後のコード(NG)
- インターフェース
public interface ITable {
public void setField1(String field1);
public void setField2(String field2);
public void save();
}
- エンティティ
@Entity
@Table(name = "HOGE")
public class Hoge extends Model implements ITable {
public String field1;
public String field2;
@Override
public void save() {
super.save();
}
// 以下を追加
@Override
public void setField1(String field1) {
this.field1 = field1;
}
@Override
public void setField2(String field2) {
this.field2 = field2;
}
}
※Fugaも同様
- 呼び出し元
public void execute() {
ITable table = createEntity(); // HogeかFugaを返すファクトリ
table.setField1("aaa");
table.setField2("bbb");
table.save();
}
修正後のNG挙動
field1とfield2を設定しているが、Ebeanが更新対象として認識せずに
insertまたはupdateが実行されない。
教訓
- インターフェースを実装するだけなら無害、という思い込みは危ない