Jersey客户端将json响应读入自定义对象

时间:2014-09-16 03:29:21

标签: json jersey jackson

public class RESTDataServiceClient{    
    private Client client;
    private String dataServiceUri;
    private String dataServiceResource;    
    private CustomData customData;

    public RESTDataServiceClient(String dataServiceUri, String dataServiceResource, Client client){
        this.client = client;
        this.dataServiceUri = dataServiceUri;
        this.dataServiceResource = dataServiceResource;
    }

    @Override
    public CustomData getCustomData() {
        WebTarget dataServiceTarget = client.target(dataServiceUri).path(dataServiceResource);
        Invocation.Builder invocationBuilder = dataServiceTarget.request(MediaType.APPLICATION_JSON_TYPE);
        Response response = invocationBuilder.get();
        myCustomData = response.readEntity(CustomData.class);
        return myCustomData;
    }
}

CustomData.java
public class CustomData{
        private TLongObjectMap<Map<String, TIntIntMap>> data;
        public CustomData() {
            this.data = new TLongObjectHashMap<>();
    }
    //getter and setter
}

示例json内容

 {"50000":{"testString":{"1":10}},"50001":{"testString1":{"2":11}} }

我正在尝试从数据服务获取数据,该服务将以JSON格式返回数据。我正在尝试编写一个客户端,将JSON读入自定义对象。 CustomData包含嵌套的宝库地图数据结构。我们为此编写了一个自定义序列化程序,服务器部分工作正常。我无法让其他客户端将数据读入对象,但读取字符串工作。我尝试使用示例数据粘贴上面的代码,我得到以下错误。

javax.ws.rs.ProcessingException: Error reading entity from input stream.
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:866)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:783)
    at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
    at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:111)
    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:399)
    at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108)
    at com.sample.data.RESTDataServiceClient.getCustomData(RESTDataServiceClient.java:42)

Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "50000" (class com.sample.data.CustomData), not marked as ignorable (0 known properties: ])
 at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@2cb89281; line: 1, column: 14] (through reference chain: com.sample.data.CustomData["50000"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
    at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:671)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:773)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1297)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1275)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:247)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
    at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1233)
    at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:677)
    at com.fasterxml.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:777)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:264)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:234)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:154)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1124)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:851)
    ... 38 more

1 个答案:

答案 0 :(得分:1)

TLongObjectMap无法开箱即用,因此您如何制作自定义序列化程序还需要实现自定义反序列化程序。您可以将它们很好地打包到模块中,然后将其添加到ObjectMapper

It looks like there is a Trove module in development right now,您可以下载并添加到ObjectMapper,与下面的示例相同。该链接中的TIntObjectMapDeserializer实现比我的解决方案更强大,因此如果可能,我建议在项目中使用该类。

如果您想尝试自己编写,这里是一个正确反序列化您提供的示例的起点:

public class FakeTest {
    @Test
    public void test() throws Exception {
        ObjectMapper om = new ObjectMapper();
        om.registerModule(new CustomModule());
        String s = "{\"50000\":{\"testString\":{\"1\":10}},\"50001\":{\"testString1\":{\"2\":11}} }";
        CustomData cd = om.readValue(s, CustomData.class);
        System.out.println(cd.getData());
    }

    public static class CustomData {
        private TLongObjectMap<Map<String, TIntIntMap>> data;

        public CustomData() {
            this.data = new TLongObjectHashMap<>();
        }

        public TLongObjectMap<Map<String, TIntIntMap>> getData() { return data; }

        public void setData(TLongObjectMap<Map<String, TIntIntMap>> data) { this.data = data; }
    }

    public static class CustomModule extends SimpleModule {
        public CustomModule() {
            addSerializer(CustomData.class, new CustomSerializer());
            addDeserializer(CustomData.class, new CustomDeserializer());
        }

        public static class CustomSerializer extends JsonSerializer<CustomData> {
            @Override
            public void serialize(CustomData value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                // add custom serializer here
            }
        }

        public static class CustomDeserializer extends JsonDeserializer<CustomData> {
            @Override
            public CustomData deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                TLongObjectMap<Map<String, TIntIntMap>> data = new TLongObjectHashMap<>();
                ObjectNode node = jsonParser.getCodec().readTree(jsonParser);
                Iterator<Map.Entry<String,JsonNode>> fields = node.fields();
                while (fields.hasNext()) {
                    Map.Entry<String, JsonNode> entry = fields.next();
                    ObjectNode value = (ObjectNode) entry.getValue();
                    Map.Entry<String, JsonNode> innerField = value.fields().next();
                    ObjectNode innerNode = (ObjectNode) innerField.getValue();
                    Map.Entry<String, JsonNode> innerInnerField = innerNode.fields().next();
                    TIntIntMap intMap = new TIntIntHashMap();
                    intMap.put(Integer.parseInt(innerInnerField.getKey()), innerInnerField.getValue().asInt());
                    Map<String, TIntIntMap> innerMap = Collections.singletonMap(innerField.getKey(), intMap);
                    data.put(Long.parseLong(entry.getKey()), innerMap);
                }
                CustomData customData = new CustomData();
                customData.setData(data);
                return customData;
            }
        }
    }
}