Как использовать пользовательские исключения в сессионных компонентах?

EJB 3.1 Session 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 ответ

Решение

Прежде всего, вам не нужно использовать аннотацию @Local здесь. Это обозначает интерфейс как локальный интерфейс или при использовании в компоненте (в вашем случае) может использоваться для указания на локальный интерфейс (через атрибут value). Ни один из случаев не применим здесь. Ваш код, как указано, также не будет компилироваться. lookup("Foo") вернет объект, который должен быть приведен.

В любом случае, проблема заключается в том, что контейнер EJB не теряет никакой информации, а помещает ваше исключение в исключение EJBException. Это потому, что FooException в конечном итоге наследуется от RuntimeException. Любое такое исключение рассматривается контейнером как nonapplication exception и для тех спецификация EJB определяет, что они должны быть обернуты.

В вашей ситуации вы уже вышли из EJBException, поэтому кажется, что это угловой случай. JBoss AS 6, например, не делает дополнительной обертки в этой ситуации, но, очевидно, OpenEJB делает.

Вы можете решить эту проблему, либо не позволяя FooException наследоваться от EJBException, либо перехватывая исключение в своем тесте, разворачивая его и повторно выбрасывая развернутое исключение.

Поскольку ваш метод bar объявляет, что он выдает FooException, я предполагаю, что вы не понимали, что EJBException является RuntimeException и, следовательно, исключением из приложения. Почему вы позволили FooException наследоваться от EJBException? Вы думали, что это как-то требовалось, или это нужно для сервера какого-то специального назначения?

(в качестве дополнительной подсказки убедитесь, что вы понимаете разницу между приложениями и исключениями для приложений в отношении отката любой транзакции и уничтожения объединенного компонента)

Другие вопросы по тегам