7. Jackson用树模型处理JSON是必备技能,不信你看(下)

简介: 7. Jackson用树模型处理JSON是必备技能,不信你看(下)


ObjectMapper中的树模型


树模型其实是底层流式API所提出和支持的,典型API便是com.fasterxml.jackson.core.TreeNode。但通过前面文章的示例讲解可以知道:底层流式API仅定义了接口而并未提供任何实现,甚至半成品都算不上。所以说要使用Jackson的树模型还得看ObjectMapper,它提供了TreeNode等API的完整实现。


不乏很多小伙伴对ObjectMapper的树模型是一知半解的,甚至从来都没有用过,其实它是非常灵活和强大的。有了上面的基础示例做支撑,再来了解它的实现就得心应手多了。


ObjectMapper中提供了树模型(tree model) API 来生成和解析 json 字符串。如果你不想为你的 json 结构单独建类与之对应的话,则可以选择该 API,如下图所示:


image.png


ObjectMapper在读取JSON后提供指向树的根节点的指针, 根节点可用于遍历完整的树。 同样的,我们可从读(反序列化)、写(序列化)两个方面来展开。


写(序列化)


将Object写为JsonNode,ObjectMapper给我们提供了三个实用API俩操作它:


image.png


1、valueToTree(Object)


该方法属相对较为常用:将任意对象(包括null)写为一个JsonNode树模型。功能上类似于先将Object序列化为JSON串,再读为JsonNode,但很明显这样一步到位更加高效。


小贴士:高效不代表性能高,因为其内部实现好还是调用了readTree()方法的


@Test
public void test1() {
    ObjectMapper mapper = new ObjectMapper();
    Person person = new Person();
    person.setName("YourBatman");
    person.setAge(18);
    person.setDog(new Person.Dog("旺财", 3));
    JsonNode node = mapper.valueToTree(person);
    System.out.println(person);
    // 遍历打印所有属性
    Iterator<JsonNode> it = node.iterator();
    while (it.hasNext()) {
        JsonNode nextNode = it.next();
        if (nextNode.isContainerNode()) {
            if (nextNode.isObject()) {
                System.out.println("狗的属性:::");
                System.out.println(nextNode.get("name"));
                System.out.println(nextNode.get("age"));
            }
        } else {
            System.out.println(nextNode.asText());
        }
    }
    // 直接获取
    System.out.println("---------------------------------------");
    System.out.println(node.get("dog").get("name"));
    System.out.println(node.get("dog").get("age"));
}


运行程序,控制台输出:


Person(name=YourBatman, age=18, dog=Person.Dog(name=旺财, age=3))
YourBatman
18
狗的属性:::
"旺财"
3
---------------------------------------
"旺财"
3


对于JsonNode在这里补充一个要点:读取其属性,你既可以用迭代器遍历,也可以根据key(属性)直接获取,是不是和Map的使用几乎一毛一样?

2、writeTree(JsonGenerator, JsonNode)


顾名思义:将一个JsonNode使用JsonGenerator写到输出流里,此方法直接使用到了JsonGenerator这个API,灵活度杠杠的,但相对偏底层,本处仍旧给个示例玩玩吧(底层API更多详解,请参见本系列前面几篇文章):


@Test
public void test2() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = new JsonFactory();
    try (JsonGenerator jsonGenerator = factory.createGenerator(System.err, JsonEncoding.UTF8)) {
        // 1、得到一个jsonNode(为了方便我直接用上面API生成了哈)
        Person person = new Person();
        person.setName("YourBatman");
        person.setAge(18);
        JsonNode jsonNode = mapper.valueToTree(person);
        // 使用JsonGenerator写到输出流
        mapper.writeTree(jsonGenerator, jsonNode);
    }
}



运行程序,控制台输出:

{"name":"YourBatman","age":18,"dog":null}



3、writeTree(JsonGenerator,TreeNode)

JsonNode是TreeNode的实现类,上面方法已经给出了使用示例,所以本方法不在赘述你应该不会有意见了吧。


读(反序列化)


将一个资源(如字符串)读取为一个JsonNode树模型。


image.png


这是典型的方法重载设计,API更加友好,所有方法底层均为_readTreeAndClose()这个protected方法,可谓“万剑归宗”。

下面以最为常见的:读取JSON字符串为例,其它的举一反三即可。


@Test
public void test3() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18,\"dog\":null}";
    // 直接映射为一个实体对象
    // mapper.readValue(jsonStr, Person.class);
    // 读取为一个树模型
    JsonNode node = mapper.readTree(jsonStr);
    // ... 略
}


至于底层_readTreeAndClose(JsonParser)方法的具体实现,就有得捞了。不过鉴于它过于枯燥和稍有些烧脑,后面撰有专文详解,有兴趣可持续关注。


场景演练


理论和示例讲完了,光说不练假把式,下面A哥根据经验,举两个树模型的实际使用示例供你参考。


1、偌大JSON串中仅需1个值

这种场景其实还蛮常见的,比如有个很经典的场景便是在MQ消费中:生产者一般会恨不得把它能吐出来的属性尽可能都扔出来,但对于不同的消费者而言它们的所需往往是不一样的:


  • 需要较多的属性值,这时候用完全数据绑定转换成POJO来操作更为方便和合理
  • 需要1个(较少)的属性值,这时候“杀鸡岂能用牛刀”呢,这种case使用树模型来做就显得更为优雅和高效了


譬如,生产者生产的消息JSON串如下(模拟数据,总之你就当做它属性很多、嵌套很深就对了):


{"name":"YourBatman","age":18,"dog":{"name":"旺财","color":"WHITE"},"hobbies":["篮球","football"]}

这时候,我仅关心狗的颜色,肿么办呢?相信你已经想到了:树模型


@Test
public void test4() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18,\"dog\":{\"name\":\"旺财\",\"color\":\"WHITE\"},\"hobbies\":[\"篮球\",\"football\"]}";
    JsonNode node = mapper.readTree(jsonStr);
    System.out.println(node.get("dog").get("color").asText());
}


运行程序,控制台输出:WHITE,目标达成。值得注意的是:如果node.get("dog")没有这个节点(或者值为null),是会抛出NPE异常的,因此请你自己保证代码的健壮性。


当你不想创建一个Java Bean与JSON属性相对应时,树模型的所见即所得特性就很好解决了这个问题。


2、数据结构高度动态化

当数据结构高度动态化(随时可能新增、删除节点)时,使用树模型去处理是一个较好的方案(稳定之后再转为Java Bean即可)。这主要是利用了树模型它具有动态可扩展的特性,满足我们日益变化的结构:


@Test
public void test5() throws JsonProcessingException {
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18}";
    JsonNode node = new ObjectMapper().readTree(jsonStr);
    System.out.println("-------------向结构里动态添加节点------------");
    // 动态添加一个myDiy节点,并且该节点还是ObjectNode节点
    ((ObjectNode) node).with("myDiy").put("contry", "China");
    System.out.println(node);
}


运行程序,控制台输出:

-------------向结构里动态添加节点------------
{"name":"YourBatman","age":18,"myDiy":{"contry":"China"}}



说白了,也没啥特殊的。拿到一个JsonNode后你可以任意的造它,就像Map<Object,Object>一样~


总结


树模型(tree model) API比Jackson 流式(Streaming) API 简单了很多,不管是生成 json字符串还是解析json字符串。但是相对于自动化的数据绑定而言还是比较复杂的。


树模型(tree model) API在只需要取出一个大json串中的几个值时比较方便。如果json中每个(大部分)值都需要获得,那么这种方式便显得比较繁琐了。因此在实际应用中具体问题具体分析,但是,Jackson的树模型你必须得掌握。

相关文章
|
3月前
|
JSON JavaScript Java
在Java中处理JSON数据:Jackson与Gson库比较
本文介绍了JSON数据交换格式及其在Java中的应用,重点探讨了两个强大的JSON处理库——Jackson和Gson。文章详细讲解了Jackson库的核心功能,包括数据绑定、流式API和树模型,并通过示例演示了如何使用Jackson进行JSON解析和生成。最后,作者分享了一些实用的代码片段和使用技巧,帮助读者更好地理解和应用这些工具。
199 0
在Java中处理JSON数据:Jackson与Gson库比较
|
5月前
|
JSON C语言 数据格式
Python导出隐马尔科夫模型参数到JSON文件C语言读取
Python导出隐马尔科夫模型参数到JSON文件C语言读取
42 1
|
5月前
|
JSON Java API
Jackson:SpringBoot中的JSON王者,优雅掌控数据之道
【8月更文挑战第29天】在Java的广阔生态中,SpringBoot以其“约定优于配置”的理念,极大地简化了企业级应用的开发流程。而在SpringBoot处理HTTP请求与响应的过程中,JSON数据的序列化和反序列化是不可或缺的一环。在众多JSON处理库中,Jackson凭借其高效、灵活和强大的特性,成为了SpringBoot中处理JSON数据的首选。今天,就让我们一起深入探讨Jackson如何在SpringBoot中优雅地控制JSON数据。
178 0
|
7月前
|
JSON fastjson 数据格式
使用jackson和fastjson实现list与json互转
使用jackson和fastjson实现list与json互转
|
8月前
|
JSON 安全 JavaScript
Java一分钟之-JSON处理:Gson与Jackson库
本文对比介绍了Java中常用的两个JSON库Gson和Jackson。Gson以其简洁易用和自动序列化/反序列化功能受到青睐,而Jackson则以优异性能和丰富功能(如字段忽略、日期格式化)著称。文中通过代码示例展示了两者的基本用法,并讨论了常见问题及解决策略,包括时间格式处理、循环引用和类型匹配。在实际应用中,应根据性能需求、安全性和版本兼容性选择合适的库,并遵循最佳实践。
226 0
|
8月前
|
JSON fastjson Java
Spring Boot Jackson 和Fast JSON 用哪个好啊 ?
【4月更文挑战第22天】
1286 1
|
8月前
|
JSON Java Maven
使用Jackson进行 JSON 序列化和反序列化
使用Jackson进行 JSON 序列化和反序列化
163 0
|
3月前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
2月前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释
|
2月前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。

热门文章

最新文章