Search code examples
javajsonjerseyjersey-2.0

How to disable Jersey's JacksonJsonProvider auto registration so I use my own?


I have an @GET method that is annotated with a @Produces( MediaType.APPLICATION_JSON ). I'd like to see that call fail when I disable the JSON processing in Jersey, but no matter what I do it continues to generate a JSON output when I access that URL method in the browser.

When I place a breakpoint inside com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider's constructor I see it is being registered when MessageBodyFactory is instantiated. In particular, under the line:

final Set<MessageBodyReader> mbrs = Providers.getProviders(locator, MessageBodyReader.class);

The JacksonJsonProvider is discovered even though I disabled all auto-discoveries. As a result I cannot register my own which provides a custom ObjectMapper. The default one is always used instead.

The method looks like this:

@GET
@Produces( MediaType.APPLICATION_JSON )
public Status getStatus() {
    return new Status("test");   
}

In my application, I make what I believe to be the proper (even an overkill) configurations:

public class CustomResourceConfig extends ResourceConfig {

public CustomResourceConfig() {

property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(CommonProperties.JSON_PROCESSING_FEATURE_DISABLE, true);
property(CommonProperties.MOXY_JSON_FEATURE_DISABLE, true);

property(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true);
property(ServerProperties.JSON_PROCESSING_FEATURE_DISABLE, true);

property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(ClientProperties.JSON_PROCESSING_FEATURE_DISABLE, true);

packages("test.package.api");
}
}

I have placed the following configs in the web.xml:

<servlet>  
    <servlet-name>jersey-servlet</servlet-name>  
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <init-param>
        <param-name>jersey.config.server.tracing</param-name>
        <param-value>ALL</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.disableMetainfServicesLookup</param-name>
        <param-value>1</param-value>
    </init-param>

    <init-param>
        <param-name>jersey.config.disableJsonProcessing</param-name>
        <param-value>1</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.disableMoxyJson</param-name>
        <param-value>1</param-value>
    </init-param>

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.specktro.orchid.deployment.registry.CustomResourceConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>  
 </servlet>

My pom.xml includes the following dependencies:

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>
    <dependency> 
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
    </dependency>

Versions are managed by parent POM, but I need to use Jackson 2.3.2, and I'm using Jersey 2.7 (also tried with 2.6, same results).

I also tried registering a JacksonJaxbJsonProvider which used my object mapper:

register(new JacksonJaxbJsonProvider(objectMapper, null));

but that results in two JacksonJsonProviders registered: one for my JacksonJaxbJsonProvider and one that Jersey registers during initialization and that one gets used so mine is ignored.

How can I get Jersey to use my JacksonJsonProvider instead of the default one so I can provide my own ObjectMapper?

UPDATE Of course I also tried creating a custom ContextResolver that provides a custom ObjectMapper and registered it, but it is ignored.


Solution

  • Found the problem!! I was not returning an object like normally people do. Instead I was throwing a subclass of WebApplicationException which shows in the client as a JSON:

    public class ApplicationException extends WebApplicationException {
        private static final long serialVersionUID = 1L;
    
        public ApplicationException(int errorCode, String message) {
            super(Response.status(Response.Status.OK).entity(
                        JsonNodeFactory.instance.objectNode()
                        .put("errorCode", errorCode)
                        .put("errorMessage", message).toString())
                    .type(MediaType.APPLICATION_JSON).build());
        }
    
    }
    

    And THAT is a problem in Jersey... when Jersey handles this exception it does not use the correct Json Provider... instead it registers a default one without my custom settings, and also does not query for the ContextResolver I have registered resulting in an unformatted JSON (I have pretty print turned on on my ObjectMapper).

    I opened a bug with Jersey in JIRA: https://java.net/jira/browse/JERSEY-2503

    I hope this helps another poor soul trying to handle this case.