使用Jackson注入基于条件的json属性

时间:2016-07-31 12:56:40

标签: java json fasterxml

我有一个json格式,我使用Jackson API转换为Java对象模型。我正在使用Jaxsonxml 2.1.5解析器。 json响应如下所示。

 {
   "response": {
   "name": "states",
   "total-records": "1",
   "content": {
     "data": {
       "name": "OK",
       "details": {
         "id": "1234",
         "name": "Oklahoma"
       }
     }
   }
 }
}

现在json响应格式已经改变。如果total-records1,则details将是具有idname属性的对象。但如果total-records超过1,则details将是一个对象数组,如下所示:

    {
      "response": {
        "name": "states",
        "total-records": "4",
        "content": {
          "data": {
            "name": "OK",
            "details": [
              {
                "id": "1234",
                "name": "Oklahoma"
              },
              {
                "id": "1235",
                "name": "Utah"
              },
              {
                "id": "1236",
                "name": "Texas"
              },
              {
                "id": "1237",
                "name": "Arizona"
              }
            ]
          }
        }
      }
    }

我的Java Mapper类看起来像下面的json响应。

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class MapModelResponseList {

      @JsonProperty("name")
      private String name;

      @JsonProperty("total-records")
      private String records;

      @JsonProperty(content")
      private Model model;

      public Model getModelResponse() {
        return model;
      }

      public void setModel(Model model) {
        this.model = model;
      }
    }

客户代码

    package com.test.deserializer;

    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com..schema.model.Person;

    public class TestClient {

        public static void main(String[] args) {
            String response1="{\"id\":1234,\"name\":\"Pradeep\"}";
            TestClient client = new TestClient();
            try {
                Person response = client.readJSONResponse(response1, Person.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public <T extends Object> T readJSONResponse(String response, Class<T> type) {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
            T result = null;
            try {
                result = mapper.readValue(response, type);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return (T) result;
        }

    }

现在基于total-records如何处理映射到ModelModel对象列表。请告诉我。

2 个答案:

答案 0 :(得分:1)

您需要自定义反序列化程序。我们的想法是将对象处理与树处理混合和匹配。尽可能解析对象,但使用树(JSONNode)进行自定义处理。

MapModelResponseList上,删除records属性并添加List<Data>数组,其中Data只是id / name对的持有者类。您可以通过返回此列表的大小来获取总记录。

在反序列化器中,执行以下操作:

public final class MapModelDeserializer extends BeanDeserializer {
   public MapModelDeserializer(BeanDeserializerBase src) {
    super(src);
   }

  protected void handleUnknownProperty(JsonParser jp, DeserializationContext ctxt, Object beanOrClass, String propName) throws IOException, JsonProcessingException {
    if ("content".equals(propName)) {
      MapModelResponseList response = (MapModelResponseList) beanOrClass;

      // this probably needs null checks!
      JsonNode details = (JsonNode) jp.getCodec().readTree(jp).get("data").get("details");

      // read as array and create a Data object for each element
      if (details.isArray()) {
        List<Data> data = new java.util.ArrayList<Data>(details.size());

        for (int i = 0; i < details.size(); i++) {
           Data d = jp.getCodec().treeToValue(details.get(i), Data.class);
           data.add(d);
        }

        response.setData(data);
      }
      // read a single object
      else {
         Data d = jp.getCodec().treeToValue(details, Data.class);
         response.setData(java.util.Collections.singletonList(d));
      }

    super.handleUnknownProperty(jp, ctxt, beanOrClass, propName);
}   

请注意,您没有实现deserialize() - 默认实现用于正常创建MapModelResponseListhandleUknownProperty()用于处理content元素。由于超级电话中的@JsonIgnoreProperties(ignoreUnknown = true),您忽略的其他数据将被忽略。

答案 1 :(得分:0)

这是一个较晚的答案,但是我用另一种方法解决了。可以像这样在Object中捕获它来工作:

    @JsonProperty("details")
    public void setDetails(Object details) {
        if (details instanceof List) {
            setDetails((List) details);
        } else if (details instanceof Map) {
            setDetails((Map) details);
        }
    }

    public void setDetails(List details) {
        // your list handler here
    }

    public void setDetails(Map details) {
       // your map handler here
    }