Search code examples
javarestjerseyjackson

Jersey Exception mappers not working when jackson deserialization fails


I am using Jersey 2.10 with Jackson serialization/deserialization feature in my REST API.

My idea is to make my REST API to always return a standard JSON error response. For that I have ExceptionMapper classes that build proper json error responses for any exception being thrown in the Jersey application. I also have a jsp which produces the same kind of JSON response, which I registered as error-page in the web.xml that covers all the errors that could come before Jersey being loaded.

But there is one case in which neither my Exception mappers nor my json producing jsp are working, that is when sending a bad formed json to a POST REST endpoint which just returns the following message:

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
Content-Type: text/plain
Content-Length: 210
Date: Tue, 24 Jun 2014 22:14:11 GMT
Connection: close

Can not deserialize instance of com.example.rest.User[] out of START_OBJECT token
 at [Source: org.glassfish.jersey.message.internal.EntityInputStream@1dcccac; line: 1, column: 1]

How can I make Jersey to return my custom error response instead of this?

UPDATE:

Based on the answer by @Lucasz, I did more research and found that there are two Exception mappers defined inside the package com.fasterxml.jackson.jaxrs.base (https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base/src/main/java/com/fasterxml/jackson/jaxrs/base) JsonMappingExceptionMapper and JsonParseExceptionMapper that seem to be shadowing my custom mappers.

How can I unregister those mappers?

This is how I am currently registering the mappers:

@ApplicationPath("/")
public class MyApp extends ResourceConfig{
    public SyntheticAPIApp() {
        packages("com.example.resource", "com.example.mapper");
        register(org.glassfish.jersey.jackson.JacksonFeature.class);
    }
}

Solution

  • I tested it with an exception mapper like below:

    import javax.ws.rs.core.Response;
    import javax.ws.rs.core.Response.Status;
    import javax.ws.rs.ext.ExceptionMapper;
    import javax.ws.rs.ext.Provider;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    
    @Provider
    public class JsonProcessingExceptionMapper implements ExceptionMapper<JsonProcessingException>{
    
            public static class Error {
                public String key;
                public String message;
            }
    
            @Override
            public Response toResponse(JsonProcessingException exception) {
                Error error = new Error();
                error.key = "bad-json";
                error.message = exception.getMessage();
                return Response.status(Status.BAD_REQUEST).entity(error).build();
            }
    }
    

    and it worked.


    Update: changed JsonParseException to JsonProcessingException (more general)


    Update2: In order to avoid registering the unwanted mappers replace

    register(org.glassfish.jersey.jackson.JacksonFeature.class);
    

    with

    register(com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.class);
    

    Look at the source code of JacksonFeature and you'll understand what's happening.