Java JSON库支持在没有模式的情况下获取和设置深层值?

时间:2017-11-08 00:35:38

标签: java json serialization jsonpath lenses

我正在调用一些服务的API,他们返回一个巨大的JSON,其中包含大约一百个字段和十几个嵌套对象。但是,我并不需要所有这些。事实上,在进行GET或POST时,我确实需要3到7个字段。我非常希望避免在我的应用程序中使用这个复杂的模型来序列化/反序列化几个字段。

基本上,我想实现:

  1. 将其巨大的嵌套 JSON字符串反序列化为平面 POJO。
  2. 使用我的平面POJO投影在我的代码中工作。
  3. 将我的平面POJO序列化为其复杂的嵌套架构。
  4. 到目前为止,我的解决方案是依靠JsonPath

    1. 为我的单位POJO中的字段创建自定义注释,例如:
    2. @JsonPathField("$.very.deeply.nested.field.value") private String theOnlyFieldIneed;

      1. 创建一个使用反射生成<fieldName, JsonPath.readValue()>地图的util方法,我将其提供给Jackson objectMapper以生成我的POJO。因此,对平坦的POJO部分进行反序列化可以起作用。

      2. 但是,对于序列化,情况更糟,因为如果String中的路径不存在,JsonPath会抛出异常。像,

      3. // This will throw an exception: DocumentContext document = JsonPath.using(jsonPathConfig).parse("{}"); document.set("$.not.even.deepest", value);

        1. 为了解决这个问题,我添加了一个原始模式作为字符串来提供给JsonParh.parse(Pojo.Prototype),但这很丑陋,乏味且容易出错。
        2. 基本上,我正在寻找Immutable.JS的行为:Collection.SetIn

1 个答案:

答案 0 :(得分:1)

你可以使用Kson(https://github.com/kantega/kson),它对从嵌套结构中提取值有相当直接的支持。

public class DecodeExample {

public static class Address {
    final String street;
    final String zip;

    public Address(String street, String zip) {
        this.street = street;
        this.zip = zip;
    }
}

static class User {
    final String                name;
    final Address address;

    User(String name, Address address) {
        this.name = name;
        this.address = address;
    }
}

public static void main(String[] args) {

    final JsonDecoder<Address> adressDecoder =
      obj(
        field("street", stringDecoder),
        field("zip", stringDecoder.ensure(z -> z.length() < 5)), //You can add constraints right here in the converter
        Address::new
      );


    JsonResult<JsonValue> json =
      JsonParser.parse(jsonString);

    Address address =
      json.field("model").field("leader").field("address").decode(adressDecoder).orThrow(RuntimeException::new);

    System.out.println(address);

    JsonResult<Address> userAddress =
      json.field("model").field("users").index(0).field("address").decode(adressDecoder);

    System.out.println(userAddress);
}

}