JAX-RS Custom ExceptionMapper not intercept RuntimeException

15,811

Solution 1

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.

Solution 2

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…

Solution 3

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

Share:
15,811
smallufo
Author by

smallufo

A Java/Kotlin programmer twitter : http://twitter.com/smallufo

Updated on June 13, 2022

Comments

  • smallufo
    smallufo almost 2 years

    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 ?

  • James Gan
    James Gan about 11 years
    "When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception."
  • Donal Fellows
    Donal Fellows about 11 years
    @James You'd think that such things are always implemented correctly, wouldn't you? So would I, except experience tells me otherwise (I guess the implementation I'm thinking of is very fond of using HashMaps for things). The only thing you can truly count on is exact matching.
  • James Gan
    James Gan about 11 years
    I agree that software is always buggy. And we should know how to create bug report once we met it. I'm using this feature in my current project. Until now, it went well.
  • Aleksandr Dubinsky
    Aleksandr Dubinsky almost 11 years
    Why @Repository? I think you mean it should be annotated with @Component (like all other resources).
  • Rana Ghosh
    Rana Ghosh over 10 years
    I had to annotate mine with javax.ws.rs.ext.Provider. Using jersey 1.x