赞
踩
JsonPath是用来解析多层嵌套的JSON数据。可以认为JsonPath就是JSON版本的XPath。它是一种信息抽取类库,是从JSON文档中抽取指定信息的工具。JsonPath对于JSON来说,就相当于XPath之于XML。
JsonPath在线解析:https://jsonpath.com/
语法 | 含义 |
---|---|
$ | 表示根节点 |
@ | 当前节点 |
.<节点名称> | 获取子节点 |
[<节点名称1>(,<节点名称2>)] | 获取子节点,与点号不同,这里可以获取多个子节点 |
* | 匹配所有元素节点 |
.. | 获取子孙节点,无论嵌套多少层,都可以获取到 |
[<下标1>(,<下标2>)] | 表示一个或多个下标 |
[start:end:step] | 表示切片语法 |
[?(<表达式>)] | 过滤器表达式,表达式结果必须是布尔值 |
() | 支持表达式计算 |
可以在JsonPath表达式执行后进行调用,其输入表达式的结果。
函数 | 描述 | 输出 |
---|---|---|
min() | 提供数字数组的最小值 | Double |
max() | 提供数字数组的最大值 | Double |
avg() | 提供数字数据的平均值 | Double |
stddev() | 提供数字数组的标准偏差值 | Double |
length() | 提供数组的长度 | Integer |
sum() | 提供数字数组的和值 | Double |
keys() | 提供属性键(终端自键~的替代选择) | Set<E> |
concat(X) | 提供路径输出的合并版本,并添加一个新项目 | like input |
append(X) | 为 json 路径输出数组添加项目 | like input |
first() | 提供数组的第一个项目 | Depends on the array |
last() | 提供数组的最后一项 | Depends on the array |
index(X) | 提供索引数组的项: X,如果 X 为负数,则向后取值 | Depends on the array |
过滤器是用于过滤数组的逻辑表达式,一个通常的表达式形如:[?(@.age > 18)]
,可以通过逻辑表达式&&
或||
组合多个过滤器表达式,例如[?(@.price < 10 && @.category == ‘fiction’)]
,字符串必须用单引号包围,例如[?(@.color == ‘blue’)]
。
操作符 | 描述 |
---|---|
== | 等于符号,但数字1不等于字符1(1 is not equal to ‘1’) |
!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于等于 |
>= | 大于等于 |
=~ | 判断是否符合正则表达式,例如[?(@.name =~ /foo.*?/i)] |
in | 属于,例如[?(@.size in ['S', 'M'])] |
nin | 排除符号 |
size | 左侧(数组或字符串)的大小应与右侧一致 |
empty | 数组或字符串)应为空 |
subsetof | 左是右的子集 [?(@.sizes subsetof [‘S’, ‘M’, ‘L’])] |
anyof | 左与右有交集 [?(@.sizes anyof [‘M’, ‘L’])] |
noneof | 左边与右边没有交集 [?(@.sizes noneof [‘M’, ‘L’])] |
{ "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 }
JsonPath | Result |
---|---|
$.store.book[*].author | 所有书籍的作者 |
$..author | 所有作者 |
$..book[2] | 第3本数 |
$..book[0,1] | 前2本数 |
$..book[1:3] | 切片操作,从索引 1(含)到索引 3(不含)的所有书籍 |
$..book[-1:] | 倒数第一本数 |
$..book[?(@.isbn)] | 所有有 ISBN 编号的书籍 |
$.store.book[?(@.price < 10)] | 价格低于10的所有数据 |
$..book.length | 书籍的数量 |
Jayway JsonPath则提供了Java版本的实现,方便开发者进行集成使用。
Maven依赖:
<!--Json Path-->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
使用 JsonPath 最简单直接的方法是通过静态读取 API。
public class Demo { private String jsonStr = "{\n" + " \"store\": {\n" + " \"book\": [\n" + " {\n" + " \"category\": \"reference\",\n" + " \"author\": \"Nigel Rees\",\n" + " \"title\": \"Sayings of the Century\",\n" + " \"price\": 8.95\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Evelyn Waugh\",\n" + " \"title\": \"Sword of Honour\",\n" + " \"price\": 12.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Herman Melville\",\n" + " \"title\": \"Moby Dick\",\n" + " \"isbn\": \"0-553-21311-3\",\n" + " \"price\": 8.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"J. R. R. Tolkien\",\n" + " \"title\": \"The Lord of the Rings\",\n" + " \"isbn\": \"0-395-19395-8\",\n" + " \"price\": 22.99\n" + " }\n" + " ],\n" + " \"bicycle\": {\n" + " \"color\": \"red\",\n" + " \"price\": 19.95\n" + " }\n" + " },\n" + " \"expensive\": 10\n" + "}"; @Test public void test1() { List<String> authors = JsonPath.read(jsonStr, "$.store.book[*].author"); //["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] System.out.println(authors); } }
如果你只读取一次,这没有问题。如果还需要读取其他路径,这就不是办法了,因为每次调用 JsonPath.read(…) 都会对文档进行解析。为了避免这个问题,可以先解析 json。
@Test
public void test2() {
final Object document = Configuration.defaultConfiguration().jsonProvider().parse(jsonStr);
String author0 = JsonPath.read(document, "$.store.book[0].author");
String author1 = JsonPath.read(document, "$.store.book[1].author");
//Nigel Rees
System.out.println(author0);
//Evelyn Waugh
System.out.println(author1);
}
JsonPath还提供了流畅的应用程序接口。这也是最灵活的一种:
@Test
public void test3() {
DocumentContext ctx = JsonPath.parse(jsonStr);
List<String> authorsOfBooksWithISBN = ctx.read("$.store.book[?(@.isbn)].author");
//["Herman Melville","J. R. R. Tolkien"]
System.out.println(authorsOfBooksWithISBN);
//[{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},
// {"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
List<Map<String, Object>> expensiveBooks = JsonPath.using(Configuration.defaultConfiguration())
.parse(jsonStr)
.read("$.store.book[?(@.price > 10)]", List.class);
System.out.println(expensiveBooks);
}
在 Java 中使用 JsonPath 时,了解结果的预期类型非常重要。JsonPath 会自动尝试将结果转换为调用者期望的类型。
//Nigel Rees
String author = JsonPath.parse(jsonStr).read("$.store.book[0].author");
//java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
List<String> list = JsonPath.parse(jsonStr).read("$.store.book[0].author");
在评估一条路径时,你需要了解一条路径何时是确定的这一概念。如果一条路径包含以下内容,那么它就是不确定的:
..
:扫描操作符?(<expression>)
:表达式[<number>, <number>(, <number)]
:多个数组索引无限路径总是返回一个列表(由当前 JsonProvider 表示)。
默认情况下,MappingProvider SPI 会提供一个简单对象映射器。这允许你指定想要的返回类型,而 MappingProvider 会尝试执行映射。下面的示例演示了 Long 和 Date 之间的映射。
String json = "{\"date_as_long\": 1411455611975}";
Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class);
//Tue Sep 23 15:00:11 CST 2014
System.out.println(date);
如果将 JsonPath 配置为使用 JacksonMappingProvider、GsonMappingProvider 或 JakartaJsonProvider,甚至可以将 JsonPath 输出直接映射到 POJO 中。
Book book = JsonPath.parse(jsonStr).read("$.store.book[0]", Book.class);
//Book{category='reference', title='Sayings of the Century', author='Nigel Rees', price=8.95, isbn='null'}
System.out.println(book);
要获取完整的类属类型信息,请使用 TypeRef。
//注意,默认的Json-smart provider不支持TypeRef,可以使用Jackson或Gson Provider
TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
List<String> titles = JsonPath.parse(jsonStr).read("$.store.book[*].title", typeRef);
System.out.println(titles);
在Jayway JsonPath中提供了多种JsonProvider,其中默认的为JsonSmartJsonProvider。这里我们期望能够直接对读取的数据进行反序列化,这里我们选用JacksonJsonProvider,此时要求jackson-databind依赖的版本至少为2.4.5。
<!--Jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
</dependency>
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
class Book {
private String category;
private String title;
private String author;
private Double price;
private String isbn;
}
public class JsonProviderTest { private String jsonStr = "{\n" + " \"store\": {\n" + " \"book\": [\n" + " {\n" + " \"category\": \"reference\",\n" + " \"author\": \"Nigel Rees\",\n" + " \"title\": \"Sayings of the Century\",\n" + " \"price\": 8.95\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Evelyn Waugh\",\n" + " \"title\": \"Sword of Honour\",\n" + " \"price\": 12.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Herman Melville\",\n" + " \"title\": \"Moby Dick\",\n" + " \"isbn\": \"0-553-21311-3\",\n" + " \"price\": 8.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"J. R. R. Tolkien\",\n" + " \"title\": \"The Lord of the Rings\",\n" + " \"isbn\": \"0-395-19395-8\",\n" + " \"price\": 22.99\n" + " }\n" + " ],\n" + " \"bicycle\": {\n" + " \"color\": \"red\",\n" + " \"price\": 19.95\n" + " }\n" + " },\n" + " \"expensive\": 10\n" + "}"; @Test public void test() { //使用JacksonJsonProvider Configuration configuration = Configuration .builder() .mappingProvider(new JacksonMappingProvider()) .build(); ReadContext ctx = JsonPath.using(configuration).parse(jsonStr); TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {}; List<Book> books = ctx.read("$.store.book[*]", typeRef); books.forEach(System.out::println); } }
Book{category='reference', title='Sayings of the Century', author='Nigel Rees', price=8.95, isbn='null'}
Book{category='fiction', title='Sword of Honour', author='Evelyn Waugh', price=12.99, isbn='null'}
Book{category='fiction', title='Moby Dick', author='Herman Melville', price=8.99, isbn='0-553-21311-3'}
Book{category='fiction', title='The Lord of the Rings', author='J. R. R. Tolkien', price=22.99, isbn='0-395-19395-8'}
在JsonPath中创建过滤器谓词有三种不同的方法:
内联谓词是在路径中定义的谓词。
可以使用 &&
和 ||
组合多个谓词 [?(@.price < 10 && @.category == ‘fiction’)]
, [?(@.category == ‘reference’ || @.price > 10)]
。
可以使用!
来否定一个谓词 [?(!(@.price < 10 && @.category == ‘fiction’))]
。
@Test
public void test1() {
List<Map<String, Object>> books = JsonPath.parse(jsonStr)
.read("$.store.book[?(@.price < 10)]");
books.forEach(System.out::println);
//{category=reference, author=Nigel Rees, title=Sayings of the Century, price=8.95}
//{category=fiction, author=Herman Melville, title=Moby Dick, isbn=0-553-21311-3, price=8.99}
books = JsonPath.parse(jsonStr)
.read("$.store.book[?(!@.price < 10)]");
books.forEach(System.out::println);
//{category=reference, author=Nigel Rees, title=Sayings of the Century, price=8.95}
//{category=fiction, author=Herman Melville, title=Moby Dick, isbn=0-553-21311-3, price=8.99}
}
如下所示,可以使用过滤器 API 构建谓词:
@Test public void test2() { Filter cheapFictionFilter = Filter.filter( Criteria.where("price").lte(10) ); //注意路径中过滤器的占位符 ? //当提供多个过滤器时,它们将按顺序应用,其中占位符的数量必须与提供的过滤器数量相匹配。 //可以在一个过滤器操作中指定多个谓词占位符[?, ?],但两个谓词必须匹配。 List<Map<String, Object>> books = JsonPath.parse(jsonStr) .read("$.store.book[?]", cheapFictionFilter); books.forEach(System.out::println); //{category=reference, author=Nigel Rees, title=Sayings of the Century, price=8.95} //{category=fiction, author=Herman Melville, title=Moby Dick, isbn=0-553-21311-3, price=8.99} //过滤器还可以与OR和AND组合使用 Filter f = Filter.filter(Criteria.where("price").lte(10)) .and(Criteria.where("isbn").exists(true)); books = JsonPath.parse(jsonStr) .read("$.store.book[?]", f); books.forEach(System.out::println); //{category=fiction, author=Herman Melville, title=Moby Dick, isbn=0-553-21311-3, price=8.99} }
@Test
public void test3() {
//自定义谓词
Predicate booksWithISBN = new Predicate() {
@Override
public boolean apply(PredicateContext ctx) {
return ctx.item(Map.class).containsKey("isbn");
}
};
List<Map<String, Object>> books = JsonPath.parse(jsonStr)
.read("$.store.book[?]", booksWithISBN);
books.forEach(System.out::println);
//{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}
}
{ "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 }, "clothes":[ { "name":"牛仔裤", "sizes":"S", "price":94 }, { "name":"背心", "sizes":"M", "price":48 }, { "name":"裙子", "sizes":["S", "M"], "price":1.24 }, { "name":"羊毛衫", "sizes":["XS", "XL"], "price":78.99 }, { "name":"Polo衫", "sizes":["XS", "XL", "M"], "price":18.99 } ] }, "expensive":10 }
@Test public void test() { //使用JacksonJsonProvider Configuration configuration = Configuration .builder() .mappingProvider(new JacksonMappingProvider()) .build(); ReadContext ctx = JsonPath.using(configuration) .parse(jsonStr); //方式一:内联谓词 TypeRef<List<Clothes>> typeRef = new TypeRef<List<Clothes>>() {}; final List<Clothes> clothes1 = ctx.read("$.store.clothes[?(@.price > 50 || @.sizes anyof ['M'])]", typeRef); System.out.println("************** clothes1 ***************"); clothes1.forEach(System.out::println); //方式二:Filter谓词 Filter filter = Filter.filter(Criteria.where("price").gt(50)) .or(Criteria.where("sizes").anyof(Arrays.asList("M"))); //使用谓词占位符? Clothes[] clothes2 = ctx.read("$.store.clothes[?]", Clothes[].class, filter); System.out.println("************** clothes2 ***************"); for (Clothes clothes : clothes2) { System.out.println(clothes); } //方式三:自定义谓词 Predicate rule = (context) -> { final Map map = context.item(Map.class); boolean b1 = false; Object priceObj = map.getOrDefault("price", null); if (priceObj != null) { String priceStr = priceObj.toString(); Double price = 0d; try { price = Double.parseDouble(priceStr); } catch (Exception e) { } b1 = price > 50d; } boolean b2 = false; Object sizes = map.getOrDefault("sizes", null); if (sizes != null && sizes instanceof List) { List<String> sizeList = (List<String>) sizes; List<String> targetList = Arrays.asList("M"); for (String size : sizeList) { if (targetList.contains(size)) { b2 = true; break; } } } return b1 || b2; }; // 使用谓词的占位符? Clothes[] clothes3 = ctx.read("$.store.clothes[?]", Clothes[].class, rule); System.out.println("-------------- clothes3 ---------------"); for (Clothes clothes : clothes3) { System.out.println(clothes); } }
************** clothes1 ***************
Clothes{name='牛仔裤', price=94.0, sizes=S}
Clothes{name='裙子', price=1.24, sizes=[S, M]}
Clothes{name='羊毛衫', price=78.99, sizes=[XS, XL]}
Clothes{name='Polo衫', price=18.99, sizes=[XS, XL, M]}
************** clothes2 ***************
Clothes{name='牛仔裤', price=94.0, sizes=S}
Clothes{name='裙子', price=1.24, sizes=[S, M]}
Clothes{name='羊毛衫', price=78.99, sizes=[XS, XL]}
Clothes{name='Polo衫', price=18.99, sizes=[XS, XL, M]}
-------------- clothes3 ---------------
Clothes{name='牛仔裤', price=94.0, sizes=S}
Clothes{name='裙子', price=1.24, sizes=[S, M]}
Clothes{name='羊毛衫', price=78.99, sizes=[XS, XL]}
Clothes{name='Polo衫', price=18.99, sizes=[XS, XL, M]}
//language=JSON String jsonStr = "{\n" + " \"name\": \"tom\",\n" + " \"age\": 18,\n" + " \"height\": 1.77,\n" + " \"scores\": [1.1, 2.2, 3,3, 4.4, 5.5, 6.6]\n" + "}"; ReadContext ctx = JsonPath.using(Configuration.defaultConfiguration()).parse(jsonStr); Double min = ctx.read("$.scores.min()"); System.out.println(min);//1.1 Double max = ctx.read("$.scores.max()"); System.out.println(max);//6.6 Double avg = ctx.read("$.scores.avg()"); System.out.println(avg);//3.6857142857142864 Double stddev = ctx.read("$.scores.stddev()"); System.out.println(stddev);//1.7779832647682354 Double sum = ctx.read("$.scores.sum()"); System.out.println(sum);//25.800000000000004 Integer length = ctx.read("$.scores.length()"); System.out.println(length);//7 Set<String> keys = ctx.read("$.keys()"); System.out.println(keys);//[name, age, height, scores] String concat = ctx.read("$.concat(@.name, \" \", @.age)"); System.out.println(concat);//tom 18 List<Double> scores = ctx.read("$.scores.append(99.9)"); System.out.println(scores);//[1.1,2.2,3,3,4.4,5.5,6.6,99.9]
JsonPath 可以返回 Path 或 Value。Value 是默认值,也是上面所有示例的返回值。如果你更希望得到我们的查询所命中的元素的路径,这可以通过一个选项来实现。
//返回路径
Configuration configuration = Configuration
.builder()
.options(Option.AS_PATH_LIST)
.build();
List<String> pathList = JsonPath.using(configuration).parse(jsonStr).read("$..author");
System.out.println(pathList);
//["$['store']['book'][0]['author']",
// "$['store']['book'][1]['author']",
// "$['store']['book'][2]['author']","
// $['store']['book'][3]['author']"]
String str = "{\"name\": \"tom\"}";
//设置值
String newStr1 = JsonPath.parse(str)
.set("$.name", "jerry")
.jsonString();
//添加
String newStr2 = JsonPath.parse(newStr1)
.put("$", "age",17)
.jsonString();
//{"name":"jerry","age":17}
System.out.println(newStr2);
有几个选项标志可以改变JsonPath的默认行为:
@Test public void configTest1() { //language=JSON String jsonStr = "[\n" + " {\n" + " \"name\" : \"john\",\n" + " \"gender\" : \"male\"\n" + " },\n" + " {\n" + " \"name\" : \"ben\"\n" + " }\n" + "]"; //默认情况抛出异常 //com.jayway.jsonpath.PathNotFoundException: No results for path: $[1]['gender'] String gender1 = JsonPath.parse(jsonStr).read("$[1].gender"); //使用DEFAULT_PATH_LEAF_TO_NULL,会返回Null Configuration configuration = Configuration.builder() .options(Option.DEFAULT_PATH_LEAF_TO_NULL) .build(); String gender2 = JsonPath.using(configuration).parse(jsonStr).read("$[1].gender"); System.out.println(gender2);//null }
@Test public void configTest2() { String jsonStr = "[\n" + " {\n" + " \"name\" : \"john\",\n" + " \"gender\" : \"male\"\n" + " },\n" + " {\n" + " \"name\" : \"ben\"\n" + " }\n" + "]"; //默认情况下抛出异常 //java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List List<String> genders1 = JsonPath.parse(jsonStr).read("$[0].gender"); //使用ALWAYS_RETURN_LIST,返回一个列表 Configuration configuration = Configuration.builder() .options(Option.ALWAYS_RETURN_LIST) .build(); List<String> genders2 = JsonPath.using(configuration).parse(jsonStr).read("$[0].gender"); System.out.println(genders2);//["male"] }
@Test public void configTest3() { String jsonStr = "[\n" + " {\n" + " \"name\" : \"john\",\n" + " \"gender\" : \"male\"\n" + " },\n" + " {\n" + " \"name\" : \"ben\"\n" + " }\n" + "]"; //存在 ALWAYS_RETURN_LIST选项,则返回空列表 Configuration configuration1 = Configuration.builder() .options(Option.ALWAYS_RETURN_LIST, Option.SUPPRESS_EXCEPTIONS) .build(); List<String> genders1 = JsonPath.using(configuration1).parse(jsonStr).read("$[1].gender"); System.out.println(genders1);//[] //不存在 ALWAYS_RETURN_LIST选项,则返回Null Configuration configuration2 = Configuration.builder() .options(Option.SUPPRESS_EXCEPTIONS) .build(); List<String> genders2 = JsonPath.using(configuration2).parse(jsonStr).read("$[1].gender"); System.out.println(genders2);//null }
@Test public void configTest4() { String jsonStr = "[\n" + " {\n" + " \"name\" : \"john\",\n" + " \"gender\" : \"male\"\n" + " },\n" + " {\n" + " \"name\" : \"ben\"\n" + " }\n" + "]"; //存在 REQUIRE_PROPERTIES,则抛出异常 //com.jayway.jsonpath.PathNotFoundException: No results for path: $[1]['gender'] Configuration configuration1 = Configuration.builder() .options(Option.REQUIRE_PROPERTIES) .build(); // List<String> genders1 = JsonPath.using(configuration1).parse(jsonStr).read("$[*].gender"); //不存在 REQUIRE_PROPERTIES,返回["male"] Configuration configuration2 = Configuration.builder() .options() .build(); List<String> genders2 = JsonPath.using(configuration2).parse(jsonStr).read("$[*].gender"); System.out.println(genders2);//["male"] }
JsonPath 提供五种不同的 JsonProviders:
只有在应用程序初始化时,才能按演示更改配置默认值。强烈不建议在运行期间更改配置,尤其是在多线程应用程序中。
Configuration.setDefaults(new Configuration.Defaults() { private final JsonProvider jsonProvider = new JacksonJsonProvider(); private final MappingProvider mappingProvider = new JacksonMappingProvider(); @Override public JsonProvider jsonProvider() { return jsonProvider; } @Override public MappingProvider mappingProvider() { return mappingProvider; } @Override public Set<Option> options() { return EnumSet.noneOf(Option.class); } });
请注意,JacksonJsonProvider 需要 com.fasterxml.jackson.core:jackson-databind:2.4.5 的类路径,而 GsonJsonProvider 需要 com.google.code.gson:gson:2.3.1 的类路径。
Jakarta EE 9 JSON-P (JSR-342) 和 JSON-B (JSR-367) 提供程序至少需要 Java 8,并要求应用程序运行时类路径上有兼容的 JSON API 实现(如 Eclipse Glassfish 和 Eclipse Yasson);Java EE 应用程序容器也可能提供此类实现。还请注意,Apache Johnzon 尚不兼容 Jakarta EE 9 规范的类路径,如果选择 JSON-B 映射提供程序,则还必须配置和使用 JSON-P 提供程序。
Jakarta EE 9 关于 JSON 处理和数据库绑定(映射)的规范有一个特点,即 Json 数组和对象在完全解析或写入后具有不变性。为了遵守 API 规范,同时允许 JsonPath 通过添加、设置/输入、替换和删除操作来修改 Json 文档,JakartaJsonProvider 必须使用可选的 true 参数进行 initiliazed:
无论采用哪种启动模式,都支持使用 JsonPath 进行的所有查找和读取操作。默认模式所需的内存更少,性能更高。
JsonPath 2.1.0 引入了新的缓存 SPI。这允许 API 用户根据自己的需要配置路径缓存。缓存必须在首次访问前配置好,否则会产生 JsonPathException 异常。JsonPath 有两种缓存实现
com.jayway.jsonpath.spi.cache.LRUCache
(默认,线程安全)com.jayway.jsonpath.spi.cache.NOOPCache
(无缓存)如果您想实现自己的缓存,API 也很简单:
CacheProvider.setCache(new Cache() {
//Not thread safe simple cache
private Map<String, JsonPath> map = new HashMap<String, JsonPath>();
@Override
public JsonPath get(String key) {
return map.get(key);
}
@Override
public void put(String key, JsonPath jsonPath) {
map.put(key, jsonPath);
}
});
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。