Java – Dealing with Automatic Binding Exceptions in Jersey

httpjavajsonrestweb services

It's really nice to have automatic binding with Jersey-Jackson (well, I believe it's actually MOXy the one who manages the bindings), so object serialization and deserialization is done under the hood.

Examples of both that I use in my RESTful service:

@POST
@Consumes(MediaType.APPLICATION_JSON)
public String createTournament(Tournament tournament) {
    return tournamentDao.create(tournament);
}

@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("id") String id) {
    Optional<Tournament> optTournament = tournamentDao.getTournament(id);
    if (optTournament.isPresent())
        return optTournament.get();
    throw new NotFoundException();
}

But what if the serialization or the deserialization fails at some point during the process? For example, unknown fields, wrong types, illegal JSON format, etc… Well, I can't deal with this because the serialization/deserialization is happening behind the scenes and all I know is I will get an argument of type Tournament (or return it in the other case) but this assumes the process is going to be successfull.

How can I deal with this? What if I wanted to return some other kind of response for a badly formatted tournament JSON instead of having an exception thrown during a very particular point of the serialization/deserialization?

Is this possible? Also, what is the standard approach for these scenarios? What response would be appropriate for a failure during JSON processing?

Best Answer

The proper HTTP error code on input is 400: Bad Request. In the response you could go with 500.

If there is an error in marshalling or unmarshalling, an exception will be thrown which you can handle by registering an ExceptionMapper (scoll down to the Exception Mapping section). You can then determine what kind of error to throw. The JAX-RS package has a class WebApplicationException which allows you to return the common HTTP error codes. If you need to get really fancy, you can use the ResponseBuilder to fine tune the response.

I personally find it very helpful to write the javax.ws.rs.core.Application myself and override the getClasses() method like so:

public Set<java.lang.Class<?>> getClasses()
{
    Set<Class<?>> classes = new HashSet<>();

    /* add filters */
    classes.add(AuthorizationFilter.class);
    /* add resources */
    classes.add(HomeResource.class);
    classes.add(RequestsResource.class);

    /* add object serializers */
    classes.add(JsonMarshaller.class);
    classes.add(HtmlWriter.class);

    return classes;
}

Put Jersey in an embedded Jetty application (or similar) if you want to be XML-free.

This will take a lot of the mystery out of how things work. The kind of issue you are running into is why I tend to avoid the "we've done everything for you so you don't have to understand it" packages for JAX-RS. If you implement your own MessageBodyReader and MessageBodyWriter classes, you can still use a package that does all the heavy lifting but have some control over these kind of details.