我正在努力解决管理非平凡数据模型的 EJB3 类的问题。当我的容器管理的事务方法提交时,我抛出了约束验证异常。我想防止它们被包裹起来EJBException
,而是抛出一个调用者可以处理的理智的应用程序异常。
要将其包装在合适的应用程序异常中,我必须能够捕获它。大多数时候,一个简单的 try/catch 就可以完成这项工作,因为验证异常是从EntityManager
我所做的调用中引发的。
不幸的是,一些约束只在提交时检查。例如,@Size(min=1)
仅当容器管理的事务提交时,一旦它在我的事务方法结束时离开我的控制权,才会捕获对映射集合的违反。我无法捕获验证失败时抛出的异常并将其包装,因此容器将其包装在 a 中javax.transaction.RollbackException
并将其包装在cursedEJBException
中。调用者必须捕获所有EJBException
s 并深入到原因链中以试图找出它是否是一个验证问题,这真的不是很好。
我正在使用容器管理的事务,所以我的 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);
}
}
}
...AppValidationException
已检查异常或未检查异常在哪里进行了注释@ApplicationException
,因此它不会被 EJB3 包装。
有时我可以用 an 触发早期的约束违规EntityManager.flush()
并抓住它,但并非总是如此。即使这样,我也真的希望能够在提交时捕获由延迟约束检查引发的数据库级约束违规,并且这些只会在JTA提交时出现。
帮助?
已经尝试过:
Bean 托管事务将通过允许我在我控制的代码中触发提交来解决我的问题。不幸的是,它们不是一个选项,因为 bean 管理的事务不提供任何等价物TransactionAttributeType.REQUIRES_NEW
- 无法使用 BMT 暂停事务。JTA 令人讨厌的疏忽之一。
看:
- 为什么我们需要 JTA 2.0
- J2EE 中的 Bean 管理的事务暂停(不要这样做!)
...但请参阅注意事项和详细信息的答案。
javax.validation.ValidationException
是 JDK 异常;我无法修改它以添加注释@ApplicationException
以防止包装。我不能子类化它来添加注释;它是由 EclpiseLink 抛出的,而不是我的代码。我不确定标记它@ApplicationException
是否会阻止 Arjuna(AS7 的 JTA impl)将它包装在 a 中RollbackException
。
我尝试使用这样的EJB3 拦截器:
@AroundInvoke
protected Object exceptionFilter(InvocationContext ctx) throws Exception {
try {
return ctx.proceed();
} catch (ValidationException ex) {
throw new SomeAppException(ex);
}
}
...但似乎拦截器在 JTA内部触发(这是明智的并且通常是可取的)所以我想要捕获的异常还没有被抛出。
我想我想要的是能够定义一个在JTA 完成它的事情之后应用的异常过滤器。有任何想法吗?
我正在使用 JBoss AS 7.1.1.Final 和 EclipseLink 2.4.0。EclipseLink 按照这些说明作为 JBoss 模块安装,但这对于手头的问题并不重要。
更新:在对这个问题进行了更多思考之后,我意识到除了 JSR330 验证异常之外,我还真的需要能够 从数据库中捕获SQLIntegrityConstraintViolationException以及分别使用 SQLSTATE 40P01 和 40001 进行死锁或序列化失败回滚。这就是为什么试图确保提交永远不会抛出的方法不会很好地工作的原因。已检查的应用程序异常不能通过 JTA 提交抛出,因为 JTA 接口自然不会声明它们,但未经检查的带@ApplicationException
注释的异常应该可以。
似乎在任何我可以有效地捕获应用程序异常的地方,我也可以 - 尽管不那么漂亮 - 捕获 EJBException 并深入研究 JTA 异常和底层验证或 JDBC 异常,然后基于此做出决策。如果没有 JTA 中的异常过滤器功能,我可能不得不这样做。