私が欲しかったのは、可能であれば「迅速でクリーンな」ソリューションだったので、今のところ新しいフレームワークはありません(ただし、後でSpring + Hibernateスタックを使用する可能性があります)。
そのため、「Command」パターンのバリアントを含む「迅速で汚くない」ソリューションを使用することになりました。このソリューションでは、休止状態の呼び出しが、汎用Commandインターフェイスを実装する匿名の内部クラス内にカプセル化され、コマンド実行機能がHibernateセッションと例外処理を使用して呼び出します。ジェネリックビットは、executeメソッドの戻り値のタイプを変えるためのものです。
このソリューションには100%満足していません。これは、ビジネスロジックにボイラープレートコードがラップされていることを意味し(戻り値に必要な明示的なキャストに特に不満があります)、理解とデバッグが少し複雑になるためです。
ただし、反復コードの増加は依然として重要であり(メソッドあたり約10行から3〜4行)、さらに重要なことに、Hibernate処理ロジックは1つのクラスに集中しているため、必要に応じてそこで簡単に変更でき、エラーが少なくなります-傾向があります。
ここにいくつかのコードがあります:
コマンドインターフェイス:
public interface HibernateCommand<T> {
public T execute(Object... args) throws Exception;
}
実行者:
public class HibernateCommandExecuter {
private static final Logger logger = Logger.getLogger(HibernateCommandExecuter.class);
public static Object executeCommand(HibernateCommand<?> command, boolean commit, Object... args) throws RemoteException{
try {
HibernateUtil.currentSession().beginTransaction();
return command.execute(args);
} catch (HibernateException e) {
logger.error("Hibernate problem : ", e);
throw new RemoteException(e.getMessage());
}catch(Exception e){
throw new RemoteException(e.getMessage(), e);
}
finally {
try{
if(commit){
HibernateUtil.currentSession().getTransaction().commit();
}else{
HibernateUtil.currentSession().getTransaction().rollback();
}
HibernateUtil.currentSession().close();
}catch(HibernateException e){
logger.error("Error while trying to clean up Hibernate context :", e);
}
}
}
}
リモートで呼び出されるメソッドでの使用例(ただし、ローカルでも使用できます):
@Override
public AbstractTicketingClientDTO doSomethingRemotely(final Client client) throws RemoteException {
return (MyDTO) HibernateCommandExecuter.executeCommand(new HibernateCommand<MyDTO>() {
public AbstractTicketingClientDTO execute(Object...args) throws Exception{
MyDTO dto = someService.someBusinessmethod(client);
return dto;
}
},false);
}
クライアント引数がfinalとして宣言されていることに注意してください。これにより、内部クラス内で参照できるようになります。finalを宣言できない場合は、executeCommandメソッドにパラメーターとして渡すことができます。