13

My goal is to make web calls and convert returned JSON to POJOs. I'm trying to use Jersey+Jackson for this but am getting exceptions when running.

My maven pom file includes the following dependencies -

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.6</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.6</version>
</dependency>

The code I use to make fetch some data is as follows -

Client client = ClientBuilder.newBuilder()
            .register(JacksonFeature.class)
            .build();
ClientResponse response = client.target(url).request(MediaType.APPLICATION_JSON).get(ClientResponse.class);

But the following exception is throw -

javax.ws.rs.ProcessingException: Error reading entity from input stream.
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:868)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:335)
...
...
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not find a deserializer for non-concrete Map type [map type; class javax.ws.rs.core.MultivaluedMap, [simple type, class java.lang.String] -> [collection type; class java.util.List, contains [simple type, class java.lang.String]]]
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:315)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:290)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:159)
at org.codehaus.jackson.map.deser.std.StdDeserializer.findDeserializer(StdDeserializer.java:620)
at org.codehaus.jackson.map.deser.BeanDeserializer.resolve(BeanDeserializer.java:379)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._resolveDeserializer(StdDeserializerProvider.java:407)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:352)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:290)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:159)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:180)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2829)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2699)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:419)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:257)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:229)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:149)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1124)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:853)
... 90 more
Caused by: java.lang.IllegalArgumentException: Can not find a deserializer for non-concrete Map type [map type; class javax.ws.rs.core.MultivaluedMap, [simple type, class java.lang.String] -> [collection type; class java.util.List, contains [simple type, class java.lang.String]]]
at org.codehaus.jackson.map.deser.BasicDeserializerFactory.createMapDeserializer(BasicDeserializerFactory.java:424)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:380)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:310)
... 108 more

Am I missing some setup to get this to work right? I have tried the url via curl and browser and it returns JSON as expected.

ashutosh
  • 649
  • 1
  • 8
  • 21

2 Answers2

26

What you need is a Response and not a ClientResponse:

javax.ws.rs.core.Response jsonResponse = client.target(url).request(MediaType.APPLICATION_JSON).get();

Then you can see what comes in your response (debugging is your friend here). Is it by any chance a map of some type? If it is, you can read it by doing e.g.

Map<SomeClassOfYours> entitiesFromResponse = jsonResponse.readEntity(new GenericType<Map<SomeClassOfYours>>() {});

If you've put a normal entity in the response you can simply do something like:

SomeClassOfYours entityFromResponse = jsonResponse.readEntity(SomeClassOfYours.class);

Edit: For this to work you'd also need to define SomeClassOfYours and put the corresponding fields, constructor, getters and setters in there.

Edit2: When in doubt you can always read the jsonResponse as a String.class and put it in a String variable.

ingenious
  • 966
  • 10
  • 20
  • I tried this initially, but for some reason my IDE does not find readEntity in the Response object (jsonResponse). – ashutosh Feb 21 '14 at 01:46
  • Can you also please explain why I should use Response? And when would I use ClientResponse? – ashutosh Feb 21 '14 at 01:47
  • 1
    ClientResponse is a relic from jersey 1.x. See https://jersey.java.net/documentation/latest/user-guide.html#mig-1.x . What kind of error do you get, when you try using Response.readEntity()? – ingenious Feb 21 '14 at 07:44
  • 1
    Netbeans showed an exception saying that the method readEntity did not exist. But looking at the source code clearly showed the method. The code compiled but gave an error at runtime saying that the method does not exist. I later updated my java-ee-web-api from version 6 to 7 and now readEntity works fine. Thanks. – ashutosh Feb 22 '14 at 08:29
  • 1
    `client.target(url).request(MediaType.APPLICATION_JSON).get(YourClass.class)` may be more intuitive? – macemers Jul 02 '15 at 07:34
-1
Response jsonResponse = getClient().target(URI).request().get();
T result = jsonResponse.readEntity(type);
Oleksii Kyslytsyn
  • 2,458
  • 2
  • 27
  • 43
  • 7
    Answers are always stronger if you also explain your solution a bit. – Magnilex Feb 22 '15 at 09:33
  • @Magnilex the idea was to use the generic type, wrapped in javax.ws.rs.core.Response to exchange the typed instances back and forth between backend and fronend parts of the application. – Oleksii Kyslytsyn Feb 23 '15 at 09:05
  • 1
    Great. :) If I were you I would edit the question and add the explanation to it. – Magnilex Feb 23 '15 at 09:22