users@jersey.java.net

Re: [Jersey] Error pages when status != 2xx

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Sun, 30 Nov 2008 21:19:49 -0800

Rod Fitzsimmons Frey wrote:
>
> Hi there. I’m having some trouble wrapping my head around
> ResponseBuilder and how it handles error flow conditions. My apologies
> if this question belongs on another list: I’m a refugee from rails and
> I’ve not quite internalized the various boundaries.
>
> My problem is that I’d like to respond to a REST request with a
> particular error code and nothing else, but I can’t get rid of the
> default Glassfish HTML error page. I’ve got a @Post method that
> returns the created object, which is annotated with @XMLRootObject.
> Works like a champ for the regular flow, but for duplicate create
> requests I tried to send a 409 Conflict:
>
> if(userDAO.findUserByEmail(email) != null) {
>
> throw new WebApplicationException(409);
>
> }
>
> Which when invoked with curl gave me the 409 as desired, plus a big
> XHTML error page. I have also tried changing the return type to a
> Response and using
>
> return Response.noContent().status(409).build();
>
> return Response.status(409).entity("").build();
>
> return Response.status(409).build();
>
> all of which return the HTML error page. I’ve tried sending 409s to a
> blank.html page in the web.xml but that didn’t work either (I found
> out why in an archive search here:
> https://jersey.dev.java.net/servlets/ReadMsg?listName=users&msgNo=484
> <https://jersey.dev.java.net/servlets/ReadMsg?listName=users&msgNo=484>
>
> I have a feeling this is a RTFM moment but I can’t find the
> appropriate M to FR. Any help would be greatly appreciated.
>
> Rod
>
One approach to this kind of thing that I have found useful is to define
an exception class named (for this use case) ConflictException. For
convenience I use subclasses of RuntimeException so you don't have to
declare them in a throws clause (i.e. they act more like Ruby
exceptions), but different folks have different tastes about that. The
application logic would change slightly to something like:

if (userDAO.findUserByEmail(email) != null) {
throw new ConflictException("Email address '" + email + "' is already in
use");
}

Next, I provide an exception mapper class that will (as the name
implies) map an exception into a response. Something like this if you
want just a plain text message:

@Provider
public class ConflictExceptionMapper
implements ExceptionMapper<ConflictException> {

public Response toResponse(ConflictException e) {
return Response.status(409).entity(e.getMessage().build();
}

}

Provider classes (including exception mappers) in your application
classpath get recognized and registered automatically at application
startup, so no further configuration is required.

Besides giving you fine grained control over what actually *is* returned
for error use cases, this also nicely insulates your application logic
from having to know about the fact that a "key already in use" error is
modelled as a status 409.

Craig