我正在努力解決管理非平凡數據模型的EJB3類的問題。當我的容器管理的事務方法提交時,我引發了約束驗證異常。我想阻止它們被封裝在EJBException
中,而是拋出一個呼叫者可以處理的理智的應用程序異常。如何捕獲幷包裝由JTA在容器託管的tx EJB提交時拋出的異常?
要將它包裝在合適的應用程序例外中,我必須能夠抓住它。大多數情況下,一個簡單的try/catch可以完成這項工作,因爲驗證異常是從我做的一個EntityManager
調用中拋出的。
不幸的是,一些約束只在提交時檢查。例如,在映射集合上違反@Size(min=1)
時,只有在容器管理的事務提交後纔會捕獲它,一旦它在我的事務性方法結束時離開我的控制權。我無法捕捉到驗證失敗時拋出的異常並將其包裝,因此容器將其包裝在javax.transaction.RollbackException
中,並將封裝在EJBException
中。來電者必須抓住所有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。
有時我可以通過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。根據these instructions,EclipseLink作爲JBoss模塊安裝,但這對於手頭的問題無關緊要。
UPDATE:在這個問題上更多的思考之後,我已經意識到,除了JSR330驗證異常,我真的還需要能夠從DB和deadlock or serialization failure rollbacks with SQLSTATE 40P01 and 40001 respectively陷阱SQLIntegrityConstraintViolationException。這就是爲什麼只是試圖確保提交永遠不會拋出的方法將無法正常工作。檢查的應用程序異常不能通過JTA提交拋出,因爲JTA接口自然不會聲明它們,但未經檢查@ApplicationException
帶註釋的異常應該可以。
看來,我可以在任何地方有用地捕獲應用程序異常,但我也可以 - 儘管不那麼謹慎 - 捕獲EJBException並針對JTA異常和底層驗證或JDBC異常進行深入研究,然後根據該異常做出決策。如果沒有JTA中的例外過濾器功能,我可能不得不這樣做。
在我嘗試一個答案之前的澄清:'ValidationException'是第三方異常,你說?不是來自'javax.validation。*'包? – 2012-08-02 13:49:41
對不起,措辭不妙。 「我沒有在我的代碼中定義一個例外,我無法控制,也無法修改」。 'javax.validation.ValidationException'。 – 2012-08-02 23:24:30
還有最後一個問題:主動驗證(http://docs.oracle.com/javaee/6/api/javax/validation/Validator.html)是不可能的?(我認爲是這樣; EclipseLink使用代理的方式有些問題,或者阻止它在JPA提供程序提供的集合類中工作。) – 2012-08-03 00:31:23