JAX-RS自定义ExceptionMapper不拦截RuntimeException

Posted

技术标签:

【中文标题】JAX-RS自定义ExceptionMapper不拦截RuntimeException【英文标题】:JAX-RS Custom ExceptionMapper not intercept RuntimeException 【发布时间】:2011-08-12 02:53:01 【问题描述】:

我想将底层RuntimeExceptions 包装成自定义 json 格式,使 servlet 容器不会将堆栈跟踪转储到客户端。

我关注这个问题:JAX-RS (Jersey) custom exception with XML or JSON。 调用时:

try 
  doSomething(parameters);

catch(RuntimeException e) 
  throw new MyCustomException(500 , e.getMessage() , Status.INTERNAL_SERVER_ERROR);

当我故意输入错误的参数(并触发 doSomething() 抛出的 RuntimeException )时,我没有看到 MyCustomExceptionMapper 工作。相反,servlet 容器转储:

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 在 web.xml 中:

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

但为什么泽西岛似乎从不调用它?

【问题讨论】:

【参考方案1】:

我找到了解决办法。

我所要做的就是用 Spring 的 @Repository 注释 MyCustomExceptionMapper。

并删除 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 ,而 Jersey 会使用它。

【讨论】:

为什么选择@Repository?我认为你的意思是它应该用 @Component 注释(就像所有其他资源一样)。 我必须用 javax.ws.rs.ext.Provider 注释我的。使用球衣 1.x【参考方案2】:

认为(根据我的实验)异常提供程序是通过精确的类匹配而不是通过继承匹配来查找的,因此处理RuntimeException 的异常提供程序只有在以下情况下才会触发该应用程序抛出一个原始的RuntimeException;您向我们展示的课程并非如此。我有一些关于如何解决这个问题的理论(例如,使用自定义过滤器处理程序,或者可能使用 AOP),但还没有最终结果。

关于你问题的后半部分,我只是不知道。我所知道的是 Apache CXF(我使用过的 JAX-RS 实现)在这方面有/有一些失败,因此我坚持在应用程序的 Spring 配置中手动注册我所有的 @Providers。我将其作为经验提供……

【讨论】:

“在选择异常映射提供程序以映射例外时,实现必须使用通用类型是异常的最接近超级类的提供程序。” span> @James 你会认为这样的事情总是正确实现的,不是吗?我也会,除非经验告诉我(我想我正在考虑的实现非常喜欢使用HashMaps)。您唯一可以真正依靠的是精确匹配。 我同意软件总是有缺陷的。我们应该知道如何在遇到错误报告后创建错误报告。我正在我当前的项目中使用此功能。到现在为止,一切都很顺利。【参考方案3】:

您的 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

【讨论】:

【参考方案4】:

您只需要在 web.xml 中配置 servlet。您不需要将@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

测试:

泽西 v1.11 12/09/2011 10:27 AM Spring v3.1.1 GlassFish Server 开源版 3.1.2(内部版本 23)

【讨论】:

【参考方案5】:

我遇到了同样的问题,web.xml 中的更改,特别是标记解决了这个问题。 只需确保 for 包含您的异常和异常映射器类的包,而不仅仅是包含模型和资源的包 jersey.config.server.provider.packages 基础包

例如。如果模型/实体的包是 pkg.entity 并且异常是 pkg.exception 参数值(基本包)将是 pkg。如果 basepackage 设置为 pkg.entity 它不起作用...这就是我解决问题的方法。

【讨论】:

以上是关于JAX-RS自定义ExceptionMapper不拦截RuntimeException的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JAX-RS 异常上的自定义消息设置 40X 错误?

JAX-RS(泽西实现)ExceptionMapper 没有捕获ConstraintViolationException

Jersey / JAX-RS ExceptionMapper MySQL

RESTEasy中的通用异常处理ExceptionMapper

获取在 ExceptionMapper 中抛出异常的方法的 @Produces 注释

JAX-RS 和自定义授权