SpringBoot教程(11) Jackson中的JsonNode,ObjectNode,ArrayNode使用和区别

一、前言

若你的项目里使用Jackson处理JSON,必然会看到很多JsonNode、ObjectNode和ArrayNode的使用。
如果对它们概念很混淆,写代码时总是Ctrl+C别人的代码,那永远不会进步。

1. JsonNode作用

JsonNode是Jackson中为了处理JOSN文本的树模型(tree model)。可以将JSON文本转成JsonNode,也可以将JsonNode转成JOSN文本。JsonNode是只读的,不可修改,用它可以方便的获取JSON中某字段的值。

2. JsonNode VS ObjectNode

ObjectNode和ArrayNode都是JsonNode类的扩展,不同的是JsonNode是只读的,而ObjectNode和ArrayNode是可以修改的。如果只是从JSON文本中读取数据,用JsonNode就够了。

ObjectNode是一个JSON对象节点,ArrayNode就是一个数组,可以包含多个ObjectNode。

二、只读的JsonNode

1. 测试用的JSON文本

{
  "id":"09194567",
  "studentName":"王三",
  "nickName": null,
  "englishName":"King Three",
  "age":32,
  "email":"123@qq.com",
  "birthday":"1989-12-21",
  "joinDate":"2019-03-10 11:15:39",
  "courseScores":[
    {
      "course":"Java",
      "score":95
    },
    {
      "course":"C#",
      "score":94
    },
    {
      "course":"C++",
      "score":89
    }
  ],
  "courseScoresGroup":{
    "A":[
      "Java",
      "C#"
    ],
    "B":[
      "C++"
    ]
  },
  "valid":true
}

2. JSON 和 JsonNode 相互转换

使用ObjectMapper 的readTree方法可以轻松将JSON转JsonNode。

FileReader fileReader = new FileReader(OBJECT_FILE_PATH);
String studentStr = fileReader.readString();

ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(studentStr);

JsonNode 转 JSON:

String json = mapper.writeValueAsString(rootNode);

JsonNode 转 Java对象:

Student student = mapper.treeToValue(rootNode, Student.class);

3. 使用get方法取值

get方法定义如下:

public JsonNode get(String fieldName)

get方法也是返回一个JsonNode。

  • 如果 fieldName是在JSON中不存在的字段,则直接返回null。
  • 如果字段的值本来就是null,比如"nickName",那么会返回一个NullNode,这个NullNode的textValue()就是"null"。
log.info("get(\"不存在的字段\") = " +     rootNode.get("不存在的字段"));
log.info("get(\"studentName\") = " +     rootNode.get("studentName"));
log.info("get(\"nickName\") = " +        rootNode.get("nickName").textValue());
log.info("get(\"age\").intValue() = " +  rootNode.get("age").intValue());
log.info("get(\"age\").textValue() = " + rootNode.get("age").textValue());
log.info("get(\"joinDate\") = " +        rootNode.get("joinDate"));
log.info("get(\"valid\") = " +           rootNode.get("valid"));
log.info("get(\"courseScores\") = " +    rootNode.get("courseScores"));
log.info("get(\"courseScoresGroup\") = " + rootNode.get("courseScoresGroup"));

打印结果:

get("不存在的字段") = null
get("studentName") = "王三"
get("nickName") = null
get("age").intValue() = 32
get("age").textValue() = null
get("joinDate") = "2019-03-10 11:15:39"
get("valid") = true
get("courseScores") = [{"course":"Java","score":95},{"course":"C#","score":94},{"course":"C++","score":89}]
get("courseScoresGroup") = {"A":["Java","C#"],"B":["C++"]}

4. 使用path方法取值

path方法和get方法类似,但是如果取一个不存在的字段的值,返回的是MissingNode对象,它可以调用textValue(),这样的好处可以避免一些空指针问题,所以一定要注意get和path的区别。

log.info("path(\"不存在的字段\") = " +             rootNode.path("不存在的字段"));
log.info("path(\"不存在的字段\").textValue() = " + rootNode.path("不存在的字段").textValue());
log.info("path(\"studentName\") = " +            rootNode.path("studentName"));
log.info("path(\"nickName\") = " +               rootNode.path("nickName"));
log.info("path(\"age\") = " +                    rootNode.path("age"));
log.info("path(\"courseScores\") = " +           rootNode.path("courseScores"));
log.info("path(\"courseScoresGroup\") = " +      rootNode.path("courseScoresGroup"));

打印结果:

path("不存在的字段") = 
path("不存在的字段").textValue() = null
path("studentName") = "王三"
path("nickName") = null
path("age") = 32
path("courseScores") = [{"course":"Java","score":95},{"course":"C#","score":94},{"course":"C++","score":89}]
path("courseScoresGroup") = {"A":["Java","C#"],"B":["C++"]}

5. 使用at方法取值

因为JSON是有层级的数据格式,可以用at方法指定字段的路径,获取下面层级的字段。
如果指定了一个不存在的路径,返回的是MissingNode对象,这个特点和path相同。

log.info("at(\"studentName\") = " +   rootNode.at("/studentName"));

JsonNode at1 = rootNode.at("/courseScoresGroup/A");
JsonNode at2 = rootNode.at("/courseScoresGroup/E");
log.info("at(\"/courseScoresGroup/A\") = " + at1);
log.info("at(\"/courseScoresGroup/E\") = " + at2);
log.info("at(\"/courseScoresGroup/E\").textValue() = " + at2.textValue());

打印结果:

at("studentName") = "王三"
at("/courseScoresGroup/A") = ["Java","C#"]
at("/courseScoresGroup/E") = 
at("/courseScoresGroup/E").textValue() = null

三、可修改的ObjectNode

用ObjectNode可以自己构建JSON的内容,然后把ObjectNode转成JSON文本。

ObjectMapper mapper = new ObjectMapper();
ObjectNode studentNode = mapper.createObjectNode();
studentNode.put("id", "1");
studentNode.put("name", "亚瑟");
studentNode.put("age", 30);
//添加一个数组
List<CourseScore> courseScores = new ArrayList<>();
courseScores.add(new CourseScore("Java", 100));
courseScores.add(new CourseScore("C++", 90));
studentNode.put("courseScores", courseScores.toString());
System.out.println(studentNode.toPrettyString());
//删除一个属性
studentNode.remove("name");
System.out.println(studentNode.toPrettyString());

四、可修改的ArrayNode

如果属性的值是数组,你不需要对其修改时,直接用JsonNode 就行,isArray()判断是否是数组。

JsonNode courseScores = rootNode.get("courseScores");
if (courseScores.isArray() && !courseScores.isEmpty()) {
    Iterator<JsonNode> elements = courseScores.elements();
    while (elements.hasNext()) {
        JsonNode score = elements.next();
        System.out.println(score.toString());
    }
}

结果如下:

{"course":"Java","score":95}
{"course":"C#","score":94}
{"course":"C++","score":89}

如果需要对值进行修改编辑,就得用ArrayNode 。

//创建一个pythonNode 
ObjectNode pythonNode = mapper.createObjectNode();
pythonNode.put("course", "python");
pythonNode.put("score", 100);

ArrayNode arrayNode = (ArrayNode)rootNode.get("courseScores");
if (arrayNode.isArray() && !arrayNode.isEmpty()) {
    //删除第一个Java
    arrayNode.remove(0);
    
    //又添加了一个python
    arrayNode.add(pythonNode);
    Iterator<JsonNode> elements = arrayNode.elements();
    while (elements.hasNext()) {
        JsonNode score = elements.next();
        System.out.println(score.toString());
    }
}

结果如下:

{"course":"C#","score":94}
{"course":"C++","score":89}
{"course":"python","score":100}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟 王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值