Elad Benda2 Elad Benda2 - 1 year ago 86
JSON Question

how come `.readEntity(MyObj.class)` fails while `objectMapper.readValue(str, MyObj.class);` works

I have this code

import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;
/**
* Created by eladb on 9/6/16.
*/
public class DeploymentClient {

private CommonClient commonClient;


String appName = "topic-test-publisher";


public DeploymentClient(String url, InputStream clientSecretFile) {
commonClient = new CommonClient(url, clientSecretFile);
}

public VersionOld getCurrentConfigVersion(String project, String subDir) throws Exception {
VersionOld version = commonClient.authorizedRequestBuilder(commonClient.webTarget
.path("/apps/get_current_version/default/"+appName+"/"+appName)
.queryParam("object_type", "app"))
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(ClientResponse.class)
.readEntity(VersionOld.class);

return null;
}
}


and

which gives me that exception:

javax.ws.rs.client.ResponseProcessingException: com.fasterxml.jackson.databind.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.Object]]]

at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:806)
at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:700)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:696)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)


but this code works:

import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;
/**
* Created by eladb on 9/6/16.
*/
public class DeploymentClient {

private CommonClient commonClient;


String appName = "topic-test-publisher";


public DeploymentClient(String url, InputStream clientSecretFile) {
commonClient = new CommonClient(url, clientSecretFile);
}

public VersionOld getCurrentConfigVersion(String project, String subDir) throws Exception {
String str = commonClient.authorizedRequestBuilder(commonClient.webTarget
.path("/apps/get_current_version/default/"+appName+"/"+appName)
.queryParam("object_type", "app"))
.accept(MediaType.APPLICATION_JSON_TYPE)
.get()
.readEntity(String.class);



VersionOld v = foo(str);
return null;
}

public VersionOld foo(String str){
ObjectMapper objectMapper = new ObjectMapper();
VersionOld v = null;
try {
v = objectMapper.readValue(str, VersionOld.class);
} catch (Exception e) {
e.printStackTrace();
}
return v;
}
}


in both cases the http response is:

str = {"versions": {"ap": "Not Set", "am": "topic-test-publisher-1.0.16", "il": "topic-test-publisher-1.0.16", "row": "topic-test-publisher-1.0.49"}, "provider": "gce"}


how come this code works ok?

Isn't it the same logic?

Answer Source

Just replace ClientResponse with javax.ws.rs.core.Response in your client code or don't use any arguments at all.

    VersionOld version = commonClient.authorizedRequestBuilder(commonClient.webTarget
            .path("/apps/get_current_version/default/"+appName+"/"+appName)
            .queryParam("object_type", "app"))
            .accept(MediaType.APPLICATION_JSON_TYPE)
            .get(javax.ws.rs.core.Response.class)//or get().readEntity(VersionOld.class);
            .readEntity(VersionOld.class);

I believe that you used org.glassfish.jersey.client.ClientResponse but the resource returned is probably javax.ws.rs.core.Response (it has happened to me also)

I tested with the following server side code

@GET
@Path("/us")
@Produces(MediaType.APPLICATION_JSON)
public Response getJson() { //javax.ws.rs.core.Response
    VersionOld vo = new VersionOld();
    vo.versions.put("ap", "Not set");
    vo.versions.put("am", "topic-test-publisher-1.0.16");
    vo.versions.put("il", "topic-test-publisher-1.0.16");
    vo.versions.put("row", "topic-test-publisher-1.0.49");
    vo.provider = "gce";


    return Response.status(200).entity(vo).build();
}

and the POJO is defined as

public class VersionOld {

  //public variables but you can use getters/setters
public Map<String,String> versions = new HashMap<>();
public String provider;

public VersionOld(){}
  }  

The output is

Msg: topic-test-publisher-1.0.16
Msg: topic-test-publisher-1.0.49