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)
答案 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)