JAX-RS自定义ExceptionMapper不拦截RuntimeException

发布于 2024-11-02 21:43:39 字数 1889 浏览 1 评论 0原文

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

我关注这个问题: JAX-RS (Jersey) 自定义异常XML 或 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>

但为什么 Jersey 似乎从不调用它?

I want to wrap underlaying RuntimeExceptions to a custom json format , making the servlet container won't dump the stacktrace to client.

I follow this question : JAX-RS (Jersey) custom exception with XML or JSON .
When calling :

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

When I intentionally feed wrong parameters (and trigger RuntimeException thrown by doSomething() ) , I didn't see MyCustomExceptionMapper working. Instead , the servlet container dumps :

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

The MyCustomExceptionMapper is indeed registered in the 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;
  }

What did I miss ?

Thanks a lot !

Environment : JAX-RS , jersey-server 1.5

classes spec :

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

updated :

I suspect that Application.getClasses() is never called , so I add some println messages :

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

And in deed , it's never shown !

I am sure this ApiConfig is in the web.xml :

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

But why it seems Jersey never calls it ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

赏烟花じ飞满天 2024-11-09 21:43:39

我找到了解决方案。

我所要做的就是用 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 将使用它。

I found the solution.

All I have to do is annotate MyCustomExceptionMapper with Spring's @Repository.

And remove the section in web.xml (not needed)

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

Because Spring will lookup all @Repository and find a @Provider , and Jersey will make use of it.

述情 2024-11-09 21:43:39

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

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

I think (on the basis of my experiments) that exception providers are looked up by exact class match, rather than by inheritance match, so an exception provider that handles RuntimeException will only fire if the app throws a raw RuntimeException; that's not the case with the class you've showed us. I have some theories about how to fix this (e.g., with a custom filter handler, or possibly some use of AOP) but nothing final yet.

In relation to the second half of your question, I just don't know. What I do know is that Apache CXF (the JAX-RS implementation I've worked with) has/had some failings in this area, and that I thus stick to registering all my @Providers by hand in the app's Spring config. I offer that as experience…

且行且努力 2024-11-09 21:43:39

您的 web.xml 中的参数名称不正确,因此该设置被忽略。

正确的参数名称是 javax.ws.rs.Application (不是您要扩展的类 javax.ws.rs.core.Application )。

参见示例:
docs.oracle.com/cd/E24329_01/web.1211/e24983/configure.htm#RESTF179

Your web.xml had an incorrect param-name in web.xml so that setting was being ignored.

The correct param name is javax.ws.rs.Application (not javax.ws.rs.core.Application which is the class you're extending).

See for example:
docs.oracle.com/cd/E24329_01/web.1211/e24983/configure.htm#RESTF179

伊面 2024-11-09 21:43:39

您只需要在 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

测试使用:

  • Jersey v1.11 12/09/2011 10:27 AM
  • Spring v3.1.1
  • GlassFish Server Open Source Edition 3.1.2 (build 23)

You just need to configure the servlet in web.xml. You don't need to add @Repository to your 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>

When the application is deploy you can see the following lines in log file:

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

Tested with:

  • Jersey v1.11 12/09/2011 10:27 AM
  • Spring v3.1.1
  • GlassFish Server Open Source Edition 3.1.2 (build 23)
情深如许 2024-11-09 21:43:39

我遇到了同样的问题,web.xml 中的更改,特别是标签中的更改解决了该问题。
只需确保包含异常和异常映射器类的包,而不仅仅是包含模型和资源的包

jersey.config.server.provider.packages
基础包

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

I faced the same problem and the change in web.xml, in particular in tag solved the issue.
Just make sure that the for the includes your package for the exception and exception mapper classes not only the packages containing the models and resources

jersey.config.server.provider.packages
basepackage

ex. if package for models/entities is pkg.entity and for exception is pkg.exception param-value (basepackage) will be pkg. If basepackage is set pkg.entity it doesn't work...that is how i solved the issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文