Entity単位のServiceに共通の親クラスを持たせる

元ネタは続・SAStruts + S2JDBCのアーキテクチャに載っていたServiceで共通的に使うメソッドを共通親クラスに抽象化したメソッドで持たせるという考え。

ジェネリクスを使ったクラス設計なぞしたことが無い自分には良い刺激を受けました。


元記事ではユースケース単位にServiceを用意するという考えでしたが、自分としてはServiceはEntity単位に作っておいてActionでは1つまたは複数のServiceを組み合わせて使うようにしたい。

ServiceをEntity単位とした場合に元記事のAbstractServiceのままでは、例えばEmployeeエンティティ用のEmployeeServiceクラスを使ってfindAll等を使おうとした時に

employeeService.findAll(Employee.class);

となり、なんかDRYじゃない感じになる。

ServiceをEntity単位に作成するという方針にするのであれば、

employeeService.findAll();

としたい。

あと、自分は必ずActionFormとしてのDTOを使う方針にしたので、CRUD処理の引数もEntityではなくDTOを渡してEntityへの詰め替えもやらせたい。


何とか出来ないものかと試行錯誤してAbstractServiceを改変した結果が以下の通り。

public abstract class AbstractService<E> {

 // JDBCマネージャー
 public JdbcManager jdbcManager;

 // Entityのクラス
 public Class<E> clazz;

 public AbstractService(Class<E> clazz){
  this.clazz = clazz;
 }

 public <D> int insert(D dto) {
  E x = Beans.createAndCopy(clazz, dto).execute();
  return jdbcManager.insert(x).execute();
 }

 public <D> int update(D dto) {
  E x = Beans.createAndCopy(clazz, dto).execute();
  return jdbcManager.update(x).execute();
 }

 public <D> int delete(D dto) {
  E x = Beans.createAndCopy(clazz, dto).execute();
  return jdbcManager.delete(x).ignoreVersion().execute();
 }

 public E find(Integer id) {
  return jdbcManager.from(clazz).id(id).getSingleResult();
 }

 public List<E> findAll() {
  return jdbcManager.from(clazz).getResultList();
 }

 public List<E> findAll(String orderBy) {
  return jdbcManager.from(clazz).orderBy(orderBy).getResultList();
 }

 public List<E> findAllByBeanMap(BeanMap conditions,
  String leftOuterJoin, String orderBy) {
  return jdbcManager.from(clazz)
     .leftOuterJoin(leftOuterJoin)
     .where(conditions)
     .orderBy(orderBy)
     .getResultList();
 }

 public List<E> findAllBySqlFile(String sqlPath, Object parameters) {
  return jdbcManager.selectBySqlFile(clazz, sqlPath, parameters).getResultList();
 }

 public long count(BeanMap conditions) {
  return jdbcManager.from(clazz).where(conditions).getCount();
 }

 public boolean exist(Integer id) {
  Object obj = jdbcManager.from(clazz).id(id).getSingleResult();
  return obj == null ? false : true;
 }

}

Employeeエンティティ用のEmployeeServiceクラスの実装は次のような感じ。

public class EmployeeService extends AbstractService<Employee>{

 public EmployeeService(){
  super(Employee.class);
 }

 /**
  * ここに個別のメソッドを定義
  */

}

型パラメータにEmployee、コンストラクタでもEmployee.classと指定しないといけないのが冗長な感じだけど、とりあえず

    • 引数にEntityのクラスを渡さない使い方(employeeService.findAll()といった感じ)
    • CRUD処理でDTOを引数にしてEntityへ詰め替える

という目的は達成できました。

どうにかして型パラメータからAbstractServiceのclazzへセットしたかったのですが、やり方わからず。。。