JsonPath 返回类型

在 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 和 POJO 映射

如果将 JsonPath 配置为使用 JacksonMappingProviderGsonMappingProvider 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 为  JacksonMappingProviderGsonMappingProvider 或 JakartaJsonProvider,运行程序抛出如下错误:

Exception in thread "main" java.lang.UnsupportedOperationException: Json-smart provider does not support TypeRef! Use a Jackson or Gson based provider

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号