Fastjson2 JSONPath 支持

作为 Java 开发者,处理 JSON 数据时常常需要从嵌套结构中提取特定字段。传统的做法是手动解析每一层,不仅代码冗长,而且容易出错。Fastjson2 提供的 JSONPath 支持,就像给 JSON 数据装上了导航仪,让你能像使用 XPath 操作 XML 一样,快速定位 JSON 中的任意节点。

什么是 JSONPath?

JSONPath 是一种查询 JSON 数据的表达式语言,它通过路径表达式来定位 JSON 节点。Fastjson2 不仅完整实现了 JSONPath 规范,还额外支持了一些实用特性。

快速上手

1. 添加依赖

首先确保项目中引入 Fastjson2:

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.61</version>
</dependency>

2. 基础用法

假设我们有如下 JSON 数据:

{
  "store": {
    "book": [
      {
        "title": "Java 编程思想",
        "price": 89.0,
        "authors": ["Bruce Eckel"]
      },
      {
        "title": "Effective Java",
        "price": 68.0,
        "authors": ["Joshua Bloch"]
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 1999.0
    }
  }
}

通过json转字符串工具可以压缩json一行,放到下面jsonStr字符串使用。

获取所有书名

String jsonStr = "..."; // 上面 JSON 字符串
JSONObject obj = JSON.parseObject(jsonStr);

// 使用 JSONPath 提取所有书名
List<String> titles = (List<String>) JSONPath.eval(obj, "$.store.book[*].title");
System.out.println(titles); // ["Java 编程思想", "Effective Java"]

相关参数解释如下:

  • $ 表示根节点
  • .store.book 访问 store 对象下的 book 数组
  • [*] 表示数组中的所有元素
  • .title 获取每本书的 title 属性

条件过滤

获取价格大于 70 的书籍:

// 过滤条件
List<JSONObject> expensiveBooks = (List<JSONObject>) JSONPath.eval(
    obj, "$.store.book[?(@.price > 70)]"
);
expensiveBooks.forEach(book -> 
    System.out.println(book.getString("title"))
);
// 输出: Java 编程思想

参数解释:

  • [?(@.price > 70)] 是一个过滤表达式
  • ?() 表示条件判断
  • @ 代表当前正在处理的数组元素
  • .price > 70 条件是书的 price 属性大于 70

获取特定位置的元素

获取第一本书的作者:

String firstAuthor = (String) JSONPath.eval(obj, "$.store.book[0].authors[0]");
System.out.println(firstAuthor); // Bruce Eckel

参数解释 

  • $.store.book[0] 访问 book 数组的第一个元素(索引从 0 开始)
  •  .authors[0] 访问该书的 authors 数组的第一个作者

进阶特性

1. 通配符与深度查询

// 查找所有价格字段(不限层级)
List<Double> allPrices = (List<Double>) JSONPath.eval(obj, "$..price");
System.out.println(allPrices); // [89.0, 68.0, 1999.0]

// 获取所有叶节点值
List<Object> leaves = (List<Object>) JSONPath.eval(obj, "$..*");

2. 数组切片

// 获取第一本书(索引从0开始)
List<JSONObject> firstBook = (List<JSONObject>) JSONPath.eval(obj, "$.store.book[0:1]");

// 获取所有书籍(跳步取值)
List<JSONObject> oddBooks = (List<JSONObject>) JSONPath.eval(obj, "$.store.book[::2]");

3. 在 Bean 上使用 JSONPath

Fastjson2 支持对 Java 对象直接应用 JSONPath:

public class Store {
    private List<Book> book;
    private Bicycle bicycle;
}

Store store = JSON.parseObject(jsonStr, Store.class);
String title = (String) JSONPath.eval(store, "$.book[0].title");
System.out.println(title); // Java 编程思想

实用技巧

  1. 性能优化:创建一次 JSONPath 对象可重复使用:
JSONPath path = JSONPath.of("$.store.book[*].title");
List<String> titles = (List<String>) path.eval(obj);
  1. 错误处理:当路径不存在时,返回 null 而非异常:
Object result = JSONPath.eval(obj, "$.nonexistent.path");
System.out.println(result); // null
  1. 结合 Lambda:快速转换结果:
List<String> cheapTitle = JSONPath.eval(obj, "$.store.book[?(@.price < 70)].title")
    .stream()
    .map(String.class::cast)
    .collect(Collectors.toList());

总结

JSONPath 让 Fastjson2 在处理复杂 JSON 结构时变得优雅高效。掌握 JSONPath 都能让 JSON 数据处理代码量减少 50% 以上。路径语法需要多练习,建议用 JSONPath.eval() 在复杂 JSON 上尝试不同路径组合,很快就能得心应手。

Fastjson2 的 JSONPath 实现还支持更多高级用法,如正则匹配、多条件组合等。