Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey: How to register a ExceptionMapper that omits some subclasses?

Tags:

jersey

jax-rs

How do I register a catch-all ExceptionMapper<Exception> that does not intercept WebApplicationException for which Jersey provides special handling?

UPDATE: I filed this feature request: http://java.net/jira/browse/JERSEY-1607

like image 482
Gili Avatar asked Dec 05 '12 05:12

Gili


3 Answers

I ended up registering a ExceptionMapper:

import com.google.inject.Singleton;
import com.sun.jersey.api.container.MappableContainerException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
 * @author Gili Tzabari
 */
@Provider
@Singleton
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException>
{
    @Override
    public Response toResponse(RuntimeException e)
    {
        if (e instanceof WebApplicationException)
        {
            // WORKAROUND: Attempt to mirror Jersey's built-in behavior.
            // @see http://java.net/jira/browse/JERSEY-1607
            WebApplicationException webApplicationException = (WebApplicationException) e;
            return webApplicationException.getResponse();
        }
        // Jetty generates a log entry whenever an exception is thrown. If we don't register an
        // ExceptionMapper, Jersey will log the exception a second time.
        throw new MappableContainerException(e);
    }
}
like image 140
Gili Avatar answered Nov 12 '22 09:11

Gili


Take a look how it's done in ReXSL ExceptionTrap class. You don't register an ExceptionMapper to catch all exception un-caught by Jersey. Instead, you let them bubble up to the Servlet container (e.g. Tomcat), and the container will forward them to the right servlet for further handling.

The main and only purpose of ExceptionMapper is to convert certain business-specific exceptions to HTTP responses. In other words, let the application control exceptional flow of events. On the other hand, the purpose of servlet exception catching mechanism is to control application failover and do some post-mortem operations, like, for example, logging. In other words, ExceptionMapper works when you're still in control, while exception catching servlet helps when control is lost and you have to show 50x response code to the user.

Jetty logs (through JUL) every WebApplicationException if status code of its encapsulated Response is higher than 500. Runtime exceptions are not logged by Jetty, they just bubble up to the container.

like image 1
yegor256 Avatar answered Nov 12 '22 09:11

yegor256


Extend ExtendedExceptionMapper and implement isMappable(e):

@Override
public boolean isMappable(T e) {
    return !e instanceof WebApplicationException;
}
like image 1
heio Avatar answered Nov 12 '22 09:11

heio