首页 > 解决方案 > 如何在 Java 中填充 JSON 模式的字段

问题描述

我正在尝试填充 JSON 对象,因此我可以将其发送到 REST 端点并获得响应。

没有 API 可以“构建”这些请求,所以我只是存储一个如下所示的 JSON 文本文件:

"query": {
  "bool": {
    "must": [
      {
        "range": {
          "request_time": {
            "gte": {{START_TIME}},
            "lte": {{END_TIME}},
            "format": "epoch_millis"
          }
        }
      }
    ],
    "filter": [
      {
        "match_all": {}
      },
      {
        "geo_bounding_box": {
          "{{LOCATION_FIELD_NAME}}": {
            "top_left": {
              "lat": {{TOP_LEFT_LAT}},
              "lon": {{TOP_LEFT_LON}}
            },
            "bottom_right": {
              "lat": {{BOTTOM_RIGHT_LAT}},
              "lon": {{BOTTOM_RIGHT_LON}}
            }
          }
        }
      }
    ],
    "should": [],
    "must_not": []
  }
}

然后我用键、值对填充 HashMap,其中键{{*EXPRESSION*}}和值是我希望替换它们的 , 等StringsDoubles

最后,我通过文本文件搜索分隔符:{{, }},并将键替换为值。

这对我来说似乎真的是贫民窟,而且显然很难测试。我正在使用 Jackson 库来解析我的响应,它ObjectMapper可以让您将 JSON 转换为 POJO 并返回,这很好,但我不想经历定义 15 个类的麻烦,只是为了编译上面的骨架(我知道每次都一样)。是否有通过文本文件为杰克逊提供 JSON 模式并仅填充某些字段的事实上的方法?

谢谢!

标签: javajsonjacksonschemapopulate

解决方案


Jackson does have an API for manipulating JSON trees. You can use it to read your template from a file or string and then update only the parts you need to.

Use readTree to parse your template:

ObjectMapper mapper = new ObjectMapper();

ObjectNode template = (ObjectNode) mapper.readTree(
    "{\n" +
    "  \"query\": {\n" +
    "    \"bool\": {\n" +
    "      \"must\": [],\n" +
    "      \"filter\": [{\"match_all\": {}}],\n" +
    "      \"should\": [],\n" +
    "      \"must_not\": []\n" +
    "    }\n" +
    "  }\n" +
    "}");

Then locate the node you want to update with a JSON Pointer:

ArrayNode must = (ArrayNode) template.at("/query/bool/must");

And update it:

must
    .addObject()
    .with("range")
    .with("request_time")
    .put("gte", "2018-01-14T00:00:00.000Z")
    .put("lte", "2018-01-13T00:00:00.000Z")
    .put("format", "epoch_millis");

You can even mix it with the object mapping API:

ArrayNode filter = (ArrayNode) template.at("/query/bool/filter");
filter.addObject()
    .with("geo_bounding_box")
    .putPOJO(
        "custom_location",
        new GeoBoundingBox(
            new LatLon(-36.854307, 174.771923),
            new LatLon(-36.861172, 174.780636)
        )
    );

Serialisation of trees is performed the same way as with objects:

mapper
    .writerWithDefaultPrettyPrinter()
    .withoutFeatures(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
    .writeValue(System.out, template);

推荐阅读