users@jersey.java.net

Error handling with Jersey

From: Casper Bang <casper.bang_at_gmail.com>
Date: Wed, 16 Dec 2009 03:54:25 +0100

Still struggling with how to get user friendly error handling in place
with Jersey. Extending WebApplicationException or implementing
ExceptionMappers all over is very broad spectred and doesn't scale (a
lot of context specific ones). Observations:

1) Upstream servlet filters don't appear to consider entity/body content
of non-2xx responses relevant/valid. From studying the RFC I get the
impression that this is not mandated but has become the de-facto
standard - probably because browsers typically only care about the
content for a 2xx response.

2) MSIE will replace the 4xx page with it's own custom "user friendly"
version if the body is less than some arbitrary threshold.

3) Some containers like i.e. Tomcat (probably due to Apache in front)
will fall back to its own error page if the body is empty.

4) There doesn't seem to be a way to use declarative error-page setup
for this purpose, since it's not possible to get to the exception
directly nor indirectly though Jersey's "it" context. Otherwise the
web.xml file would be an obvious place to map exceptions and/or error
codes to views.

5) Manually creating the error response in the catch clause of each
resource method adds nesting and is hard to reuse. It does "feel right"
though, i.e. one could even use Jersey's Viewable support as a way to
generate truly dynamic and friendly error pages:

     try{
        ...
    }
    catch(AuthorizationException ex){
         return Response.status(401).entity(
                new Viewable("login",
                ex
                )).build();
     }

The exception instance becomes the model, so the custom jsp error page
will have access to exception message, stacktrace and whatever specific
context the user deems necessary. While the technique does work,
unfortunately it also generates an exception:

SEVERE: Servlet.service() for servlet default threw exception
java.lang.IllegalStateException
        at
org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:407)
        at
org.netbeans.modules.web.monitor.server.MonitorResponseWrapper.sendError(MonitorResponseWrapper.java:164)
        at
com.sun.jersey.spi.container.servlet.WebComponent$Writer.finish(WebComponent.java:255)




So I guess I was wondering, why require global providers of
ExceptionMapper rather than using annotations? Something along the lines
of the following:

    @GET
    @Path("/myResource")
    @ExceptionHandler(value=AuthorizationException.class, statusCode=401)
    class MyResource(){
        // Methods which throws AuthorizationExceptions
    }

Which would attach an exception handler to each and every method of
MyResource, and map AuthorizationException to a 401. The beauty of this
is that it could union several exceptions (a la Coin's multi-catch), it
could be used on a specific method and it could even include a viewable
reference.

    @GET
    @Path("/myMethod")
    @ExceptionHandler(value={IOException.class,
NullPointerException.class}, statusCode=500, "internalError")
    public Viewable myMethod() throws IOException{
        ...
    }

Anyway, just some ideas. If I am missing something about Jersey error
handling, kindly guide me to the docs.

Thanks,
Casper