如何在会话Bean中使用自定义异常?

时间:2011-03-07 09:18:23

标签: java exception ejb

EJB 3.1会话Bean:

import javax.ejb.*;
public class FooException extends EJBException {
}
@Stateless @Local
public class Foo {
  public void bar() throws FooException {
    if (/* something wrong */) {
      throw new FooException();
    }
  }
}

现在测试:

import org.junit.*;
public class FooTest {
  @Test(expected = FooException.class)
  public void testException() {
    new InitialContext().lookup("Foo").bar();
  }
}

问题是EJBException在测试中被捕获,而不是FooException。看起来EJB容器会丢失有关我的自定义异常类型的信息并抛出基本类型(EJBException)。这有什么不对? (这是OpenEJB 3.1)

1 个答案:

答案 0 :(得分:6)

首先,您不需要在此处使用@Local注释。这将接口指定为本地接口,或者在bean(在您的情况下)中使用时,可以使用指向本地接口(通过value属性)。这两种情况都不适用。您给出的代码也将无法编译。 lookup(“Foo”)将返回需要进行转换的Object。

无论如何,EJB容器都不会丢失任何信息,而是将您的异常包装在EJBException中。这是因为FooException最终继承自RuntimeException。容器将任何此类异常视为nonapplication exception,并且EJB规范定义它们应该被包装。

在你的情况下,你已经从EJBException扩展,所以看起来这是一个极端的案例。例如,JBoss AS 6在这种情况下没有进行额外的包装,但显然OpenEJB会这样做。

您可以通过不让FooException继承EJBException,或者通过捕获测试中的异常,展开它并重新抛出未包装的异常来解决此问题。

由于你的bar方法声明它抛出FooException,我的猜测是你没有意识到EJBException是一个RuntimeException,因此是一个非应用异常。你为什么让FooException继承EJBException?您是否认为这是以某种方式需要的,或者这需要服务器某些特殊目的吗?

(作为额外提示,请确保您了解应用程序和非应用程序异常之间的差异,以回滚任何事务并销毁池中的bean)