Jersey 2.6 with Jackson JSON deserialization
Asked Answered
F

2

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.

Faris answered 20/2, 2014 at 19:52 Comment(0)
C
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.

Clapper answered 20/2, 2014 at 21:20 Comment(5)
I tried this initially, but for some reason my IDE does not find readEntity in the Response object (jsonResponse).Faris
Can you also please explain why I should use Response? And when would I use ClientResponse?Faris
ClientResponse is a relic from jersey 1.x. See jersey.java.net/documentation/latest/user-guide.html#mig-1.x . What kind of error do you get, when you try using Response.readEntity()?Clapper
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.Faris
client.target(url).request(MediaType.APPLICATION_JSON).get(YourClass.class) may be more intuitive?Talkfest
H
-1
Response jsonResponse = getClient().target(URI).request().get();
T result = jsonResponse.readEntity(type);
Hermosa answered 21/2, 2015 at 20:25 Comment(3)
Answers are always stronger if you also explain your solution a bit.Cliffhanger
@Cliffhanger 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.Hermosa
Great. :) If I were you I would edit the question and add the explanation to it.Cliffhanger

© 2022 - 2024 — McMap. All rights reserved.