重要なデータモデルを管理するEJB3クラスの問題に苦労しています。コンテナ管理のトランザクションメソッドがコミットすると、制約検証の例外がスローされます。それらがラップされないようにしたいのですがEJBException
、代わりに、呼び出し元が処理できる正常なアプリケーション例外をスローします。
適切なアプリケーションの例外でそれをラップするには、私はそれを捕まえることができなければなりません。EntityManager
ほとんどの場合、検証例外は私が行った呼び出しからスローされるため、単純なtry/catchがその役割を果たします。
残念ながら、一部の制約はコミット時にのみチェックされます。たとえば@Size(min=1)
、マップされたコレクションに対する違反は、コンテナ管理のトランザクションがコミットされたときにのみキャッチされ、トランザクションメソッドの最後で制御が解除されます。検証が失敗したときにスローされた例外をキャッチしてラップできないため、コンテナーはそれをajavax.transaction.RollbackException
でラップし、それをcursedでラップしEJBException
ます。呼び出し元はすべてをキャッチEJBException
し、原因チェーンに飛び込んで、それが検証の問題であるかどうかを確認する必要がありますが、これは実際には良くありません。
コンテナ管理のトランザクションを使用しているので、EJBは次のようになります。
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER
class TheEJB {
@Inject private EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public methodOfInterest() throws AppValidationException {
try {
// For demonstration's sake create a situation that'll cause validation to
// fail at commit-time here, like
someEntity.getCollectionWithMinSize1().removeAll();
em.merge(someEntity);
} catch (ValidationException ex) {
// Won't catch violations of @Size on collections or other
// commit-time only validation exceptions
throw new AppValidationException(ex);
}
}
}
...ここで、 EJB3によってラップされないように、チェックされAppValidationException
た例外またはチェックされていない例外に注釈が付けられます。@ApplicationException
時々、私はとで早期の制約違反を引き起こし、EntityManager.flush()
それを捕まえることができますが、常にではありません。それでも、コミット時に遅延制約チェックによってスローされたデータベースレベルの制約違反をトラップできるようにしたいと思っています。これらの違反は、JTAがコミットしたときにのみ発生します。
ヘルプ?
すでに試しました:
Beanで管理されるトランザクションは、私が制御するコード内でコミットをトリガーできるようにすることで、私の問題を解決します。残念ながら、Bean管理のトランザクションは同等のものを提供しないため、これらはオプションではありませんTransactionAttributeType.REQUIRES_NEW
。BMTを使用してトランザクションを一時停止する方法はありません。JTAの厄介な見落としの1つ。
見る:
- JTA2.0が必要な理由
- J2EEでのBean管理のトランザクションの一時停止(これは行わないでください!)
...ただし、警告と詳細については回答を参照してください。
javax.validation.ValidationException
JDKの例外です。折り返しを防ぐために注釈を追加する@ApplicationException
ように変更することはできません。注釈を追加するためにサブクラス化することはできません。私のコードではなく、EclpiseLinkによってスローされます。マークを付けると、@ApplicationException
Arjuna(AS7のJTA impl)がRollbackException
とにかくそれをラップするのを止めることができるかどうかはわかりません。
私は次のようなEJB3インターセプターを使用しようとしました:
@AroundInvoke
protected Object exceptionFilter(InvocationContext ctx) throws Exception {
try {
return ctx.proceed();
} catch (ValidationException ex) {
throw new SomeAppException(ex);
}
}
...しかし、インターセプターはJTA内で発砲するようです(これは賢明で通常は望ましいことです)ので、私がキャッチしたい例外はまだスローされていません。
私が望んでいるのは、 JTAが処理を実行した後に適用される例外フィルターを定義できるようにすることだと思います。何か案は?
私はJBossAS7.1.1.FinalとEclipseLink2.4.0を使用しています。EclipseLinkは、これらの手順に従ってJBossモジュールとしてインストールされますが、目前の問題ではそれほど重要ではありません。
更新:この問題についてさらに検討した結果、JSR330検証の例外に加えて 、DBからのSQLIntegrityConstraintViolationExceptionと、それぞれSQLSTATE40P01および40001でのデッドロックまたはシリアル化の失敗のロールバックをトラップできる必要があることに気付きました。そのため、コミットがスローされないようにするだけのアプローチはうまく機能しません。チェックされたアプリケーション例外は、JTAインターフェースが自然に宣言しないため、JTAコミットを介してスローすることはできませんが、チェックされていない@ApplicationException
注釈付き例外はスローできるはずです。
アプリケーションの例外を便利にキャッチできるところならどこでも、あまりきれいではありませんが、EJBExceptionをキャッチし、その内部でJTA例外と、基になる検証またはJDBC例外を調べて、それに基づいて意思決定を行うことができるようです。JTAの例外フィルター機能がなければ、おそらくそうしなければならないでしょう。