How to extract ObjectMapper from JAX-RS Client?
Asked Answered
D

3

15

I am using Jersey JAX-RS client (version 2.0). I know it is using a Jackson ObjectMapper to generate and parse JSON. I want to use that same object to generate JSON for some java classes so that I can write them to a log.

I know I can create a new instance of ObjectMapper but I prefer to request Jersey Client to give me a reference to the one it is using. How can I do this? Jersey 2.0 is aware of Jackson because it includes a JacksonFeature class that is used to configure the Jackson feature in the first place.

Diaphane answered 4/5, 2013 at 23:56 Comment(0)
D
23

I solved this by adding the following static members:

private static JacksonJsonProvider jackson_json_provider = new JacksonJaxbJsonProvider()
      .configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
      .configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

private static ObjectMapper object_mapper = jackson_json_provider.locateMapper(
      Object.class, MediaType.APPLICATION_JSON_TYPE);

private static Client client = ClientBuilder.newClient().register(jackson_json_provider);

Note that the second declaration is not needed just to configure FAIL_ON_UNKNOWN_PROPERTIES or FAIL_ON_EMPTY_BEANS; I use object_mapper for some other reasons.

Diaphane answered 5/5, 2013 at 23:39 Comment(2)
If you only have client, how could you extract objectMapper from client?Mensural
@DerekY I am not sure how to do that.Diaphane
D
20

Jersey does not actually explicitly configure an ObjectMapper instance, rather it delegates to JacksonJsonProvider, which in turn uses a default mapper instance. You can trace through the JacksonProviderProxy code to see how it works. You can create and customize a shared mapper to be used throughout your application by defining a context resolver:

@Provider
public class ObjectMapperContextResolver implements
        ContextResolver<ObjectMapper> {
    private ObjectMapper mapper = null;

    public ObjectMapperContextResolver() {
        super();

        // Illustrate configuration of the mapper instance
        mapper = new ObjectMapper().configure(
                SerializationConfig.Feature.WRAP_ROOT_VALUE, true).configure(
                DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}

The Jackson provider will retrieve its mapper instance from this resolver, and you could do the same in your code, as so:

public class MyResource {
    @Context
    private ContextResolver<ObjectMapper> mapperResolver;

    public void someResourceMethod() {
        final ObjectMapper mapper = mapperResolver.getContext(Object.class);
    }
}
Driscoll answered 5/5, 2013 at 12:48 Comment(3)
thank you. how does this compare to my 3 lines of code: private static JacksonJsonProvider ... (not legible as comment so i have added it as an answer)Diaphane
also, looking at the dependency injections i wonder if your method work for jersey client? or only jersey server?Diaphane
@Diaphane Client client = ClientBuilder.newClient(); client.register(ObjectMapperContextResolver.class);Maxilliped
C
3

Was not able to get to the jersey object mapper to configure it, based on the other solutions here (using jackson 2.8.3). (I suspect it may be related to osgi container, but nonetheless...) A brute-force way around it is to get the Response object from the Client and invoke your own instance of ObjectMapper on it. Then that same instance can be reused with your explicit configuration elsewhere as well.

Client client = ClientBuilder.newClient();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
...
Response r = client.target(URL).request().get();
MyDtoClass dto = mapper.readValue((InputStream)(r.getEntity()), MyDtoClass.class);
Cranial answered 11/1, 2018 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.