How to figure out original exception responsible for transaction rollback in the JAX-RS exception mapper

huangapple 未分类评论69阅读模式
英文:

How to figure out original exception responsible for transaction rollback in the JAX-RS exception mapper

问题

Translated Content:

在这种情况下:在 Wildfly 15 上部署了一个 REST API 和一个 EJB 服务器 bean。REST 调用会启动一个事务并触发一个自定义的 CDI 事件。在我的服务器 bean 中,有一个带有事务阶段 BEFORE_COMPLETION 的事务观察方法。在某些条件下,在此方法内部会故意抛出一个带有特定消息的自定义类型的运行时异常。我希望在这种情况下回滚事务(这也是正确的)。触发回滚的异常,我想在 JAX-RS 异常映射器中处理,最终从异常发送特定的 HTTP 响应代码和消息。

现在,几乎所有的东西都按照我想要的方式工作:事务被回滚,异常映射器方法介入并处理异常。

但是我的一个大问题是:我在异常映射器中收到的参数异常类型是 javax.transaction.RollbackException,而不是我最初抛出的预期自定义类型。确切的消息是:“javax.transaction.RollbackException: ARJUNA016053: 无法提交事务。”而且,我的异常似乎没有嵌套在任何地方,例如作为原因或在接收到的异常的调用堆栈中,所以我无法弄清楚我的消息,也无法将此回滚与由于其他原因(例如数据库错误等)导致的其他潜在回滚区分开。

问题:我上面描述的期望的想法是否可能?也许我完全误解了框架的行为,因为我在 Java EE 方面缺乏经验,这种情况根本无法按这种方式工作?知道这一点对我来说已经很有帮助了。否则,我应该怎么做才能让它工作,或者我应该如何通过其他方法实现期望的结果?

以下是我当前的代码:

服务器 Bean

import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.enterprise.event.TransactionPhase;
import javax.transaction.Transactional;

import my.custom.package.CustomRuntimeException

@Stateless
@Transactional
public class CustomBean
{
    public void onNewCustomEvent(
        @Observes( during = TransactionPhase.BEFORE_COMPLETION ) CustomEvent event )
    {
        // 做一些操作
        
        if ( isSomeError )
        {
            throw new CustomRuntimeException("一些重要的详细信息。");
        }
    }
}

异常映射器

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class CustomRuntimeExceptionMapper implements ExceptionMapper<Throwable>
{
    @Override
    public Response toResponse(Throwable e) // <--- 期望:CustomRuntimeException,接收:RollbackException
    {
        // 评估异常并发送适当的 HTTP 状态码
        return Response.status(Response.Status.NOT_FOUND).build();
    }
}

异常类

public class CustomRuntimeException extends RuntimeException
{
    public CustomRuntimeException(String errorReason)
    {
        super(errorReason);
    }
}

2020-08-17. 附加备注。
在服务器日志中,我注意到了这个错误消息,也许它有助于更好地理解原因。我搜索了这个问题,但找不到有用的信息。

WELD-000401: 通知事件 null 的观察者 [UnbackedAnnotatedMethod] public CustomBean.onCustomEvent(@Observes CustomEvent) 失败。
 CustomRuntimeException

注意:我只返回了翻译好的内容,如果还有其他问题或需要进一步讨论,请继续提问。

英文:

What the circumstances are: There is a REST API and a EJB server bean deployed on Wildfly 15. The REST call starts a transaction and fires a custom CDI event. In my server bean, there is a transactional observer method with transaction phase BEFORE_COMPLETION. Under some conditions, inside of this method a runtime exception of a custom type with a specific message is intentionally thrown. I expect the transaction to be rolled back in this case (which also correctly happens). The exception which has triggered the rollback, I want to handle in a JAX-RS exception mapper and finally send a specific HTTP response code and message from the exception.

Now, almost everything works as I want: the transaction is rolled back, the exception mapper method jumps in and handles the exception.

But my big problem is: the exception which I receive as argument in exception mapper, is of type javax.transaction.RollbackException and not of my expected custom type which was initially thrown. The exact message is: "javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction." Also, my exception seems not to be nested anywhere e.g. as cause or in the call stack of the received exception, so I cannot figure out, what is my message, and also I would not be able to distinguish this rollback from another potential rollbacks due to other reasons (like database errors etc.)

Question: is my desired idea described above possible at all? Maybe I completely misunderstand how the framework acts due to my lack of Java EE experience and this scenario fundamentally cannot work this way? To know this would already be helpful to me. Otherwise, what should I do to get it work or how could I achieve the desired result with an other approach?

Here is my current code:

Server Bean

import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.enterprise.event.TransactionPhase;
import javax.transaction.Transactional;

import my.custom.package.CustomRuntimeException

@Stateless
@Transactional
public class CustomBean
{
    public void onNewCustomEvent(
        @Observes( during = TransactionPhase.BEFORE_COMPLETION ) CustomEvent event )
    {
        // do something
        
        if ( isSomeError )
        {
            throw new CustomRuntimeException(&quot;Some important detail message.&quot;);
        }
    }
}

Exception Mapper

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class CustomRuntimeExceptionMapper implements ExceptionMapper&lt; Throwable &gt;
{
    @Override
    public Response toResponse( Throwable e ) // &lt;--- Expect: CustomRuntimeException, receive: RollbackException
    {
        // evaluate the exception and send proper HTTP code
        return Response.status( Response.Status.NOT_FOUND ).build();
    }
}

Exception Class

public class CustomRuntimeException extends RuntimeException
{
    public CustomRuntimeException(String errorReason)
    {
        super (errorReason);
    }
}

2020-08-17. Additional remark.
In the server logs I noticed this error message, maybe it is helpful to better understand the reason. I googled for this, but could not figure out anything useful.

WELD-000401: Failure while notifying an observer [UnbackedAnnotatedMethod] public CustomBean.onCustomEvent(@Observes CustomEvent) of event null.
 CustomRuntimeException

答案1

得分: 0

实际上,您可以将此注解放在您的自定义异常上:

@javax.ejb.ApplicationException(rollback=true)
public class CustomRuntimeException extends RuntimeException{...}

这样,该异常将直接报告给客户端(未经包装)。

默认情况下,EJB容器会将您的自定义异常包装在EJBException中,通过使用此注解,异常将不会被包装。

但在您的情况下,可能还有其他异常或回滚是原因,而不是CustomAppException,请尝试调试您的代码执行,以找出实际发生了什么,或者提供完整的代码,以便我们尝试提供帮助。

英文:

Actually you can put this annotation on your custom exception

@javax.ejb.ApplicationException(rollback=true)
public class CustomRuntimeException extends RuntimeException{...}

So that the exception will be reported to the client directly (unwrapped).

By default, the EJB Container will wrap your custom exception by EJBException, and by using this annotation the exception will not be wrapped.

But in your case may be there another exception or a rollback is the cause, not the CustomAppException try debugging your code execution to find out what actually is going on or provide the full code so we can try to help.

huangapple
  • 本文由 发表于 2020年8月14日 18:11:37
  • 转载请务必保留本文链接:https://java.coder-hub.com/63410812.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定