JAX-RS Jersey Client marshaling JSON response with POJO MAPPING & Jackson
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);
NBW
Updated on July 11, 2020Comments
-
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 almost 12 yearsI'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 almost 12 yearsMy 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 almost 12 yearsI added the CONFIG output. Nothing jumps out as being the issue.
-
NBW almost 12 yearsThis exact approach works. See my amended comments above for the details of what was wrong.
-
pulkitsinghal almost 11 yearsGood 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