【发布时间】:2012-07-31 06:18:10
【问题描述】:
我正在努力解决管理非平凡数据模型的 EJB3 类的问题。当我的容器管理的事务方法提交时,我抛出了约束验证异常。我想防止它们被包裹在EJBException 中,而是抛出一个调用者可以处理的合理的应用程序异常。
要将其包装在合适的应用程序异常中,我必须能够捕获它。大多数时候,一个简单的 try/catch 就可以完成这项工作,因为验证异常是从我进行的 EntityManager 调用中引发的。
不幸的是,某些约束仅在提交时检查。例如,映射集合上的@Size(min=1) 违规只有在容器管理的事务提交时才会被捕获,一旦它在我的事务方法结束时离开我的控制。我无法捕获验证失败时引发的异常并将其包装,因此容器将其包装在javax.transaction.RollbackException 中并将that 包装在受诅咒的EJBException 中。调用者必须捕获所有 EJBExceptions 并深入原因链以尝试找出它是否是一个验证问题,这真的不好。
我正在处理容器管理的事务,所以我的 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 包装。
有时我可以使用EntityManager.flush() 触发早期约束违规并抓住它,但并非总是如此。即便如此,我真的也希望能够在提交时捕获由延迟约束检查引发的数据库级约束违规,并且这些只会在 JTA 时出现永远提交。
帮助?
已经尝试过:
Bean 管理的事务 将通过允许我在我控制的代码中触发提交来解决我的问题。不幸的是,它们不是一个选项,因为 bean 管理的事务不提供任何等效的 TransactionAttributeType.REQUIRES_NEW - 没有办法使用 BMT 暂停事务。 JTA 令人讨厌的疏忽之一。
见:
...但请参阅注意事项和详细信息的答案。
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 完成它的事情之后应用的异常过滤器。有什么想法吗?
我正在使用 JBoss AS 7.1.1.Final 和 EclipseLink 2.4.0。 EclipseLink 根据these instructions 安装为 JBoss 模块,但这对于手头的问题并不重要。
更新:在对这个问题进行了更多思考之后,我意识到除了 JSR330 验证异常之外,我真的还需要能够从 DB 中捕获 SQLIntegrityConstraintViolationException 和 deadlock or serialization failure rollbacks with SQLSTATE 40P01 and 40001 respectively .这就是为什么试图确保提交永远不会抛出的方法不会很好地工作的原因。已检查的应用程序异常不能通过 JTA 提交抛出,因为 JTA 接口自然不会声明它们,但未检查的 @ApplicationException 注释异常应该可以。
似乎在任何我可以有效地捕获应用程序异常的地方,我也可以 - 尽管不那么漂亮 - 捕获 EJBException 并深入研究 JTA 异常和底层验证或 JDBC 异常,然后基于此做出决策。如果没有 JTA 中的异常过滤器功能,我可能不得不这样做。
【问题讨论】:
-
在我尝试回答之前澄清一下:
ValidationException是第三方例外,你说?不是来自javax.validation.*包? -
抱歉,措辞不佳。 “我没有在我的代码中定义的一个我无法控制也无法修改的异常”。
javax.validation.ValidationException. -
最后一个问题:主动验证 (docs.oracle.com/javaee/6/api/javax/validation/Validator.html) 是不可能的? (我想它是;EclipseLink 使用代理的方式有一些问题,或者有一些东西阻止了它在 JPA 提供者提供的集合类上工作。)
-
@LairdNelson Flushing 实体管理器会自动进行验证。它对抛出SQLIntegrityConstraintViolationException 的数据库级约束没有帮助,我也想处理这些约束,而且我仍然看到 ValidationExceptions 能够通过的奇怪情况,尽管进行了积极的刷新和手动验证。我还不确定为什么,但我希望能够过滤和包装它们。
-
您可以使用 XML 描述符来注释不受您控制(第 3 方)的代码(异常)。
标签: jakarta-ee jpa ejb eclipselink jboss7.x