使用 Jackson 根据条件注入 json 属性

Injecting json property based on condition using Jackson

我有一个 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 映射器 class 看起来像下面的早期 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 对象列表。请告诉我。

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

MapModelResponseList 上,删除 records 属性 并添加一个 List<Data> 数组,其中 Data 只是一个持有者 class 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),您不关心的其他数据将被忽略。

这是一个迟到的答案,但我用不同的方式解决了它。它可以通过像这样在 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
    }