JAX-RS Jersey Client marshaling JSON response with POJO MAPPING & Jackson

25,301

To enable POJO mapping on the client side, just do :

ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);
Share:
25,301
NBW
Author by

NBW

Updated on July 11, 2020

Comments

  • NBW
    NBW almost 4 years

    I'm having a bit of an issue using Jersey client (1.11) with JSONConfiguration.FEATURE_POJO_MAPPING set to true. My test code looks like this:

    MyFooCollectionWrapper<MyFooDTO> resp
        = webResource.accept(MediaType.APPLICATION_JSON)
          .get(new GenericType<MyFooCollectionWrapper<MyFooDTO>>() {});
    

    On the server:

    1) my web.xml has POJO Mapping set to true.

    2) MyFooDTO is simply a POJO that looks like this:

    public class MyFooDTO {
    
    private long id;
    private String propA;
    
    pubic long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    
    pubic String getPropA() {
        return propA;
    }
    public void setPropA(String propA) {
        this.propA = propA;
    }
    
    public MyFooDTO(MyFoo aFoo) {
        this.id = aFoo.getId();
        this.propA = aFoo.getPropA();
    }
    
        public MyFooDTO() {}
    
    }
    

    3) MyFooCollectionWrapper looks like this:

    public class MyFooCollectionWrapper<T> extends MyFooCollectionWrapperBase {
    
        Collection<T> aCollection;
    
        public MyFooCollectionWrapper() {
            super();
        }
    
        public MyFooCollectionWrapper(boolean isOK, String msg, Collection<T> col) {
            super(isOK, msg);
            this.aCollection = col;
        }
    
        public void setCollection(Collection<T> collection) {
            this.aCollection = collection;
        }
    
        @JsonProperty("values")
        public Collection<T> getCollection() {
            return aCollection;
        }
    }
    
    public class MyFooCollectionWrapperBase {
    
        private boolean isOK;
        private String message;
    
        public MyFooCollectionWrapperBase() {
            this.message = "";
            this.isOK = false;
        }
    
        public MyFooCollectionWrapperBase(boolean ok, String msg) {
            this.isOK = ok;
            this.message = msg;
        }
    
        .. standard getter/setters ..
    
    }
    

    I've verified server has no problem creating the Json response. I can retrieve with my Jersey client code if I set the response type to String. When I use

    MyFooCollectionWrapper<MyFooDTO> resp = webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<MyFooCollectionWrapper<MyFooDTO>>() {});
    

    I would expect POJO mapping to just work (marshall the response) without any need for a custom message body reader. However, I get:

    Jun 04, 2012 3:02:20 PM com.sun.jersey.api.client.ClientResponse getEntity
    SEVERE: A message body reader for Java class com.foo.MyFooCollectionWrapper, and Java type     com.foo. MyFooCollectionWrapper<com.foo.MyFooDTO>, and MIME media type application/json was not found
    Jun 04, 2012 3:02:20 PM com.sun.jersey.api.client.ClientResponse getEntity
    SEVERE: The registered message body readers compatible with the MIME media type are:
    application/json ->
    com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
    com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$App
    com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$App
    com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
    com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$App
    */* ->
    com.sun.jersey.core.impl.provider.entity.FormProvider
    com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
    com.sun.jersey.core.impl.provider.entity.StringProvider
    com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
    com.sun.jersey.core.impl.provider.entity.FileProvider
    com.sun.jersey.core.impl.provider.entity.InputStreamProvider
    com.sun.jersey.core.impl.provider.entity.DataSourceProvider
    com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
    com.sun.jersey.core.impl.provider.entity.ReaderProvider
    com.sun.jersey.core.impl.provider.entity.DocumentProvider
    com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
    com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
    com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
    com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
    com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$General
    com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$General
    com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
    com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
    com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
    com.sun.jersey.core.impl.provider.entity.EntityHolderReader
    com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
    com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
    com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy
    com.sun.jersey.moxy.MoxyMessageBodyWorker
    com.sun.jersey.moxy.MoxyListMessageBodyWorker
    
    
    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class com.foo.MyFooCollectionWrapper, and Java type com.foo. MyFooCollectionWrapper<com.foo. MyFooDTO>, and MIME media type application/json was not found
      at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:550)
      at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:524)
      at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686)
      at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:74)
      at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:508)
    

    The class path on the client side test includes:

    jersey-test-framework-core-1.11.jar 
    jersey-test-framework-embedded-glassfish-1.11.jar 
    jersey-test-framework-grizzly-1.11.jar 
    jersey-test-framework-http-1.11.jar 
    jersey-test-framework-inmemory-1.11.jar 
    jackson-core-asl.jar 
    jackson-jaxrs.jar 
    jackson-xc.jar 
    jackson-client.jar 
    jersey-client.jar 
    jersey-core.jar 
    jersey-json.jar 
    jettison.jar
    

    Are my expectations wrong or am I missing something obvious here?

    As a side note, if I add JAXB annotations to my entities (@XmlRootElement on MyFooCollectionWrapper and MyFooDTO) the using the same webResource get call, the client I do not get a message body reader exception, however, the response is marshaled such that MyFooCollectionWrapper looks ok but its collection does not contain a MyFooDTO it contains an XML Document with the proper values in the nodes/attrs - in other words MyFooDTP doesn't get marshaled.

    When setting java.util.logging to CONFIG as was suggested in an Answer I see the following, though nothing jumps out to me. Here's a link to the output which I put on pastebin because of the length.

    Thanks,

    -Noah

    UPDATE - SOLVED

    Originally my client and client config were being created like so:

    Client rootClient = new Client();
    ClientConfig clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
    Client client = new Client(rootClient, clientConfig);
    

    When I changed this to simply

        ClientConfig clientConfig = new DefaultClientConfig();
        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
        Client client = Client.create(clientConfig);
    

    Things worked. It appears the rootClient was overriding the clientConfig on the new client. It seems odd that when you use a constructor that specifies a ClientConfig the ClientConfig gets overridden by the rootClients config.

  • NBW
    NBW almost 12 years
    I'm already doing all that. That's what the first sentence of my question above, "I'm having a bit of an issue using Jersey client (1.11) with JSONConfiguration.FEATURE_POJO_MAPPING set to true" is referring to.
  • NBW
    NBW almost 12 years
    My code actually does have the no arg constructor, I'd left it out of the sample above though so I've added it. So even though it does have a no-arg I still have this issue.
  • NBW
    NBW almost 12 years
    I added the CONFIG output. Nothing jumps out as being the issue.
  • NBW
    NBW almost 12 years
    This exact approach works. See my amended comments above for the details of what was wrong.
  • pulkitsinghal
    pulkitsinghal almost 11 years
    Good answer. This is essential when configuring JerseyTest too, otherwise only the server part of a JerseyTest will work with POJOs and the client in your test class will fail: java.net/projects/jersey/lists/users/archive/2011-07/message‌​/43