【问题标题】:How to tell Jackson to make a sub-element the top level element如何告诉杰克逊使子元素成为顶级元素
【发布时间】:2023-03-20 12:00:01
【问题描述】:

我知道如何解开杰克逊的Object,但我找不到任何关于如何解开两层的示例。

Sharepoint API 端点以以下格式返回所有内容:

{
    "d": {
        "results": [
            {
               /* lots objects with lots of properties 
                  that are irrelevant to the question */
            }
        ]
    }
}

我尝试了以下方法,但它没有使 results 值成为顶级对象。

this.om.readerFor(new TypeReference<List<User>>() {})
       .withRootName("d")
       .readValue(response.parseAsString());

我如何告诉Jackson 开始将results 解析为顶级Array 无需创建自定义对象层次结构 并且无需编写自定义反序列化器。我有一个自定义对象,它被注释为它将填充,我想要 TypeSafety 所以 Map&lt;String,Object&gt; 不是我想要的。

【问题讨论】:

    标签: java jackson jackson-databind


    【解决方案1】:

    可能不是最有效的方法,但可以尝试先将对象解析为树,然后导航到您需要的节点。像这样:

    mapper.readerFor(new TypeReference<List<User>>() {}).readValue(mapper.readTree(json).get("d").get("results"))‌​;
    

    更容易阅读:

    mapper.convertValue(mapper.readTree(json).get("d").get("‌​results"), new TypeReference<List<User>>() {});
    

    【讨论】:

    • 我独立想出了这个解决方案的变体,我认为这是得到我想要的最好的方法。
    • 至于效率,无论如何它都必须解析一次,因此传入JsonNode 开始转换在任何有意义的方式上都不会降低效率。这只是做它通常做的事情,但在两个明确的阶段。如果它必须在spacetime 中非常高效,我不会使用Json 更不用说SharePoint :-)
    • @JarrodRoberson 是的,我也认为这里的性能没什么大不了的。实际上我发布了我从未测试过性能,总是依赖别人的话。在基本测试之后:gist.github.com/varren/…time 来看,它看起来并没有那么糟糕,对于用户中有 1 个字段的简单案例可能会慢 2 倍,对于复杂的 json 可能会慢 30%。从空间角度来看,i.stack.imgur.com/bftGe.png 的效率也比包装对象或自定义反序列化器或内联 JsonParser 低 2 倍@
    【解决方案2】:
    @JsonRootName("d")
    class Data {
        public Map<String, Object>[] results;
    }
    
    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    
    Map<String, Object> results = new LinkedHashMap<>();
    results.put("key1", "val1");
    results.put("key2", "val2");
    
    Data expected = new Data();
    expected.results = new Map[1];
    expected.results[0] = results;
    
    String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(expected);
    Data actual = mapper.readerFor(Data.class).readValue(json);
    

    Json 字符串看起来像:

    {
      "d" : {
        "results" : [ {
          "key1" : "val1",
          "key2" : "val2"
        } ]
      }
    }
    

    P.S.如果你不关心concreate对象并且Map&lt;String, Object&gt;对你来说是可以的,那么你可以这样使用。

    Map<String, Object> results = (Map<String, Object>)((List<?>)mapper.readerFor(Map.class).<Map<String, Map<String, ?>>>readValues(json).next().get("d").get("results")).get(0);
    

    【讨论】:

    • “无需创建对象层次结构” - 正如我在问题中所述,我不想为此设置一个特殊的类。
    • 如果您不关心具体对象并且 Map 适合您,那么我认为您可以这样做: Map results = (Map)((List>)mapper.readerFor(Map.class).>>readValues(json).next().get("d").get("结果")).get(0);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-06
    相关资源
    最近更新 更多