me

Mateus Costa

How to Override Jersey's Jackson Exceptions

These days I was working with Jetty (version 2.19) to build a Restful API and it’s come in hand with Jackson. What it means that some basic JSON validations will happen automagically. Nice, right? Hum…Let’see.

Consider a post endpoint where is necessary to send a startTime in a date format like yyyy-MM-dd’T’HH:mm:ss and you send something in the wrong format, like below:

{
  "description": "string ",
  "type": "RUNNING",
  "startTime": "21"
}

And the message that you receive back is something like:

Failed to parse Date value '21' (format: "yyyy-MM-dd'T'HH:mm:ss"): Unparseable date: "21" (through reference chain: de.egym.recruiting.codingtask.domain.Exercise["startTime"])

Or Worst, for another error:

Unexpected character ('t' (code 116)): was expecting double-quote to start field name
 at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@8c0a6b1; line: 4, column: 4]

Ok, the message is understandble, and I think almost any developer would be capable to came through the problem. But when thinking about robust, clean and understandable APIs, is good to give more information and a more structured response for errors for who is using (imagine the scenario where you could validate all the fields from body at once).

Solution

After some research I discover that was just a matter to implement the ExceptionMapper interface.

@Provider
public class JsonMappingExceptionResponse implements ExceptionMapper<JsonMappingException> {

    @Override
    public Response toResponse(JsonMappingException exception) {
        return errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), exception.getOriginalMessage());
    }
}

Where basically I was including the body to be customized, adding just one part from the exception message that I was receiving.

Restart the server (I was using Jetty) and didn’t work =/
Again, after some research I discovered that was necessary to exclude one specific provider from my web.xml related to Jackson to override the exception that I wanted:

<init-param>
	<param-name>jersey.config.server.provider.classnames</param-name>
		<param-value>
			com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider
		</param-value>
</init-param>

After this I got my new Jackson’s error messages working:

 {
  "errorCode": 400,
  "errorValue": "Failed to parse Date value '21' (format: \"yyyy-MM-dd'T'HH:mm:ss\"): Unparseable date: \"21\""
}

The message is clearer than before and hides unnecessary details, like the object that holds startTime property. I hope you enjoy =)