JAX-RS Custom ExceptionMapper не перехватывает RuntimeException - PullRequest
6 голосов
/ 25 апреля 2011

Я хочу обернуть подложку RuntimeExceptions в пользовательский формат json, чтобы контейнер сервлета не выгружал трассировку стека на клиент.

Я следую за этим вопросом: JAX-RS (Джерси)пользовательское исключение с XML или JSON .При вызове:

try {
  doSomething(parameters);
}
catch(RuntimeException e) {
  throw new MyCustomException(500 , e.getMessage() , Status.INTERNAL_SERVER_ERROR);
}

Когда я намеренно вводил неправильные параметры (и триггер RuntimeException, брошенный doSomething()), я не видел, как MyCustomExceptionMapper работает.Вместо этого дамп контейнера сервлетов:

The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
api.MyCustomException: (underlaying msgs)

MyCustomExceptionMapper действительно зарегистрирован в javax.ws.rs.core.Application:

  @Override
  public Set<Class<?>> getClasses()
  {
    Set<Class<?>> set = new HashSet<Class<?>>();
    set.add(other classes);
    set.add(MyCustomExceptionMapper.class);
    return set;
  }

Что я пропустил?

Спасибомного!

Среда: JAX-RS, jersey-server 1.5

Спецификация классов:

class MyCustomException extends RuntimeException 
@Provider
class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException>

обновление :

Я подозреваю, что Application.getClasses() никогда не вызывается, поэтому я добавляю несколько сообщений println:

  @Override
  public Set<Class<?>> getClasses()
  {
    System.out.println("\n\n\n\n ApiConfig getClasses");
  }

И на самом деле, он никогда не отображается!

Я уверен, что этот ApiConfig находится в сети.xml:

  <context-param>
    <param-name>javax.ws.rs.core.Application</param-name>
    <param-value>destiny.web.api.ApiConfig</param-value>
  </context-param>

Но почему Джерси так не называет?

Ответы [ 5 ]

2 голосов
/ 25 апреля 2011

Я нашел решение.

Все, что мне нужно сделать, это аннотировать MyCustomExceptionMapper с помощью Spring's @Repository.

И удалите раздел в web.xml (не нужен)

  <context-param>
    <param-name>javax.ws.rs.core.Application</param-name>
    <param-value>destiny.web.api.ApiConfig</param-value>
  </context-param>

Поскольку Spring выполнит поиск всех @Repository и найдет @Provider, а Джерси воспользуется им.

1 голос
/ 27 января 2014

В файле web.xml указано неправильное имя параметра в файле web.xml, поэтому настройка игнорируется.

Правильное имя параметра - javax.ws.rs.Application (не javax.ws.rs.core.Application, который является классом, который вы расширяете).

См. Например: docs.oracle.com/cd/E24329_01/web.1211/e24983/configure.htm#RESTF179

1 голос
/ 25 апреля 2011

I думаю (на основании моих экспериментов), что провайдеры исключений ищутся по точному совпадению классов, а не по совпадению наследования, поэтому провайдер исключений, который обрабатывает RuntimeException, будет срабатывать только в том случае, если приложение выбрасывает raw RuntimeException; это не относится к классу, который вы нам показали. У меня есть несколько теорий о том, как это исправить (например, с помощью специального обработчика фильтра или, возможно, некоторого использования AOP), но пока что ничего окончательного.

Что касается второй половины вашего вопроса, я просто не знаю. Что я знаю, так это то, что Apache CXF (реализация JAX-RS, с которой я работал) имеет / имел некоторые ошибки в этой области, и поэтому я продолжаю регистрировать все свои @Provider вручную в конфигурации Spring приложения. Я предлагаю это как опыт ...

0 голосов
/ 31 марта 2016

Я столкнулся с той же проблемой, и изменение в web.xml, в частности в теге, решило проблему. Просто убедитесь, что for включает ваш пакет для исключений и классов сопоставления исключений, а не только пакеты, содержащие модели и ресурсы. jersey.config.server.provider.packages basepackage

ех. если пакет для моделей / сущностей - это pkg.entity, а для исключения - pkg.exception, значением параметра (basepackage) будет pkg. Если basepackage установлен pkg.entity, он не работает ... вот как я решил проблему.

0 голосов
/ 14 мая 2012

Вам просто нужно настроить сервлет в web.xml.Вам не нужно добавлять @Repository в свой ExceptionMapper.

<servlet>
    <servlet-name>rest-servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>your.base.package.to.rest</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>rest-servlet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

При развертывании приложения вы можете увидеть следующие строки в файле журнала:

INFO: Scanning for root resource and provider classes in the packages:
your.base.package.to.rest

INFO: Root resource classes found:
class your.base.package.to.rest.resources.FooResource

INFO: Provider classes found:
class your.base.package.to.rest.providers.NotFoundMapper

Протестировано с:

  • Jersey v1.11 12.09.2011 10:27
  • Spring v3.1.1
  • GlassFish Server с открытым исходным кодом, выпуск 3.1.2 (сборка 23)
...