在 Java 中使用 JsonPath 时,了解结果的预期类型非常重要。JsonPath 会自动尝试将结果转换为调用者期望的类型。例如:
// 将抛出 java.lang.ClassCastException 错误,字符串不能转换成 List List<String> list = JsonPath.parse(json).read("$.store.book[0].author"); // 正常工作 String author = JsonPath.parse(json).read("$.store.book[0].author");
下面提供一个完整示例:
package com.hxstrive.json_path; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import java.util.List; import java.util.Map; /** * Jayway JsonPath 示例 * @author hxstrive.com */ public class Demo5 { public static void main(String[] args) { String json = "{" + " \"store\": {" + " \"book\": [" + " {" + " \"category\": \"reference\"," + " \"author\": \"Nigel Rees\"," + " \"title\": \"Sayings of the Century\"," + " \"price\": 8.95" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Evelyn Waugh\"," + " \"title\": \"Sword of Honour\"," + " \"price\": 12.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Herman Melville\"," + " \"title\": \"Moby Dick\"," + " \"isbn\": \"0-553-21311-3\"," + " \"price\": 8.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"J. R. R. Tolkien\"," + " \"title\": \"The Lord of the Rings\"," + " \"isbn\": \"0-395-19395-8\"," + " \"price\": 22.99" + " }" + " ]," + " \"bicycle\": {" + " \"color\": \"red\"," + " \"price\": 19.95" + " }" + " }," + " \"expensive\": 10" + "}"; Object document = Configuration.defaultConfiguration().jsonProvider().parse(json); // 获取所有书籍的作者 List<String> authors = JsonPath.read(document, "$.store.book[*].author"); System.out.println("authors=" + authors); // 获取所有书籍的价格 List<Float> prices = JsonPath.read(document, "$.store.book[*].price"); System.out.println("prices=" + prices); // 获取所有书籍的信息 List<Map<String,Object>> books = JsonPath.read(document, "$.store.book[*]"); System.out.println("books=" + books); } }
运行示例,输出如下:
authors=["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] prices=[8.95,12.99,8.99,22.99] books=[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
注意:在评估 JsonPath 路径时,你需要了解路径何时是“确定”的这一概念。如果一条路径包含以下内容,那么它就是不“确定”的:
..:深度扫描操作符
?(<expression>):过滤表达式
[<number>, <number> (, <number>)]:多个数组索引
不确定路径总是返回一个列表(由当前 JsonProvider 表示)。
By default a simple object mapper is provided by the MappingProvider SPI. This allows you to specify the return type you want and the MappingProvider will try to perform the mapping. In the example below mapping between Long and Date is demonstrated.
默认情况下,MappingProvider SPI 提供一个简单的对象映射器,您可以通过它指定所需的返回类型,然后映射提供程序会尝试执行映射。下面的示例演示了 Long 和 Date 之间的映射。
// JSON 字符串 String json = "{\"date_as_long\" : 1411455611975}"; // 手动指定返回类型为 Date Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class);
我们再来看一个完整的示例,代码如下:
package com.hxstrive.json_path; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import java.util.List; import java.util.Map; /** * Jayway JsonPath 示例 * @author hxstrive.com */ public class Demo6 { public static void main(String[] args) { String json = "{" + " \"store\": {" + " \"book\": [" + " {" + " \"category\": \"reference\"," + " \"author\": \"Nigel Rees\"," + " \"title\": \"Sayings of the Century\"," + " \"price\": 8.95" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Evelyn Waugh\"," + " \"title\": \"Sword of Honour\"," + " \"price\": 12.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Herman Melville\"," + " \"title\": \"Moby Dick\"," + " \"isbn\": \"0-553-21311-3\"," + " \"price\": 8.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"J. R. R. Tolkien\"," + " \"title\": \"The Lord of the Rings\"," + " \"isbn\": \"0-395-19395-8\"," + " \"price\": 22.99" + " }" + " ]," + " \"bicycle\": {" + " \"color\": \"red\"," + " \"price\": 19.95" + " }" + " }," + " \"expensive\": 10" + "}"; // 获取所有书籍的作者,返回 List 类型 List<?> authors = JsonPath.parse(json).read("$.store.book[*].author", List.class); System.out.println("authors=" + authors); // 获取自行车颜色,返回 String 类型 String color = JsonPath.parse(json).read("$.store.bicycle.color", String.class); System.out.println("color=" + color); // 获取自行车价格,返回 Float 类型 Float price = JsonPath.parse(json).read("$.store.bicycle.price", Float.class); System.out.println("price=" + price); } }
运行示例,输出如下:
authors=["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] color=red price=19.95
如果将 JsonPath 配置为使用 JacksonMappingProvider、GsonMappingProvider 或 JakartaJsonProvider,甚至可以将 JsonPath 输出直接映射到 POJO 中。例如:
Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class);
要获取完整的泛型类型信息,请使用 TypeRef 类型,例如:
// 指定类型,List<String> TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {}; // 使用 TypeRef 类型 List<String> titles = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[*].title", typeRef);
该实例将使用 JacksonJsonProvider 和 JacksonMappingProvider,因此需要先引入 Jackson 的 maven 依赖,如下:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency>
Java 代码如下:
package com.hxstrive.json_path; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.TypeRef; import com.jayway.jsonpath.spi.json.JacksonJsonProvider; import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; import com.jayway.jsonpath.spi.mapper.MappingProvider; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Jayway JsonPath 示例 * @author hxstrive.com */ public class Demo8 { public static void main(String[] args) { String json = "{" + " \"store\": {" + " \"book\": [" + " {" + " \"category\": \"reference\"," + " \"author\": \"Nigel Rees\"," + " \"title\": \"Sayings of the Century\"," + " \"price\": 8.95" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Evelyn Waugh\"," + " \"title\": \"Sword of Honour\"," + " \"price\": 12.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"Herman Melville\"," + " \"title\": \"Moby Dick\"," + " \"isbn\": \"0-553-21311-3\"," + " \"price\": 8.99" + " }," + " {" + " \"category\": \"fiction\"," + " \"author\": \"J. R. R. Tolkien\"," + " \"title\": \"The Lord of the Rings\"," + " \"isbn\": \"0-395-19395-8\"," + " \"price\": 22.99" + " }" + " ]," + " \"bicycle\": {" + " \"color\": \"red\"," + " \"price\": 19.95" + " }" + " }," + " \"expensive\": 10" + "}"; // 手动设置 JsonProvider 和 MappingProvider 采用 Jackson 实现 Configuration.setDefaults(new Configuration.Defaults() { @Override public JsonProvider jsonProvider() { return new JacksonJsonProvider(); } @Override public Set<Option> options() { return new HashSet<>(); } @Override public MappingProvider mappingProvider() { return new JacksonMappingProvider(); } }); // 定义引用类型 TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {}; // 获取所有书籍的作者 List<String> authors = JsonPath.parse(json).read("$.store.book[*].author", typeRef); System.out.println("authors=" + authors); } } // 输出结果: //authors=[Nigel Rees, Evelyn Waugh, Herman Melville, J. R. R. Tolkien]
注意:如果不手动调用 Configuration.setDefaults() 设置 provider 为 JacksonMappingProvider、GsonMappingProvider 或 JakartaJsonProvider,运行程序抛出如下错误:
Exception in thread "main" java.lang.UnsupportedOperationException: Json-smart provider does not support TypeRef! Use a Jackson or Gson based provider