Jackson解析Json数据

1.概述

Jackson 和 FastJson 一样,是一个 Java 语言编写的,可以进行 JSON 处理的开源工具库,Jackson 的使用非常广泛,Spring 框架默认使用 Jackson 进行 JSON 处理。

Jackson 有三个核包,分别是 Streaming、Databid、Annotations,通过这些包可以方便的对 JSON 进行操作。

  • Streamingjackson-core 模块。 定义了一些流处理相关的 API 以及特定的 JSON 实现。
  • Annotationsjackson-annotations 模块,包含了 Jackson 中的注解。
  • Databindjackson-databind 模块, 在 Streaming 包的基础上实现了数据绑定,依赖于 StreamingAnnotations 包。

得益于 Jackson 高扩展性的设计,有很多常见的文本格式以及工具都有对 Jackson 的相应适配,如 CSV、XML、YAML 等。

2.Jackson Maven 依赖

在使用 Jackson 时,大多数情况下我们只需要添加 jackson-databind 依赖项,就可以使用 Jackson 功能了,它依赖了下面两个包。

  • com.fasterxml.jackson.core:jackson-annotations
  • com.fasterxml.jackson.core:jackson-core
xml 复制代码
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <!-- 引入单元测试模块 -->
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <!-- 引入lombok模块 -->
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
        </dependency>
    </dependencies> 

3.ObjectMapper 对象映射器

ObjectMapper 是 Jackson 库中最常用的一个类,使用它可以进行 Java 对象和 JSON 字符串之间快速转换。 Jackson 中的 ObjectMapper 就如同 FastJson 中的 JSON 类。

这个类中有一些常用的方法:

  • readValue() 方法可以进行 JSON 的反序列化操作,比如:将字符串、文件流、字节流、字节数组等转换成 Java 对象。
  • writeValue() 方法可以进行 JSON 的序列化操作,可以将 Java 对象转换成 JSON 字符串。

大多数情况下,ObjectMapper 的工作原理是通过 Java Bean 对象的 Get/Set 方法进行转换时映射的,所以正确编写 Java 对象的 Get/Set 方法尤为重要,不过 ObjectMapper 也提供了诸多配置,比如可以通过配置或者注解的形式对 Java 对象和 JSON 字符串之间的转换过程进行自定义。

4.Jackson JSON 基本操作

4.1 Jackson JSON 序列化

编写一个 Person 类,定义三个属性,名称、年龄以及技能, 将 Java 对象(Person)转换成 JSON 字符串。

java 复制代码
import lombok.Data;
import java.util.List;
// Person 类
@Data
public class Person {
    private String name;
    private Integer age;
    private List<String> skillList;
}

// 将Person转换为Json对象
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import java.util.Arrays;

public class PersonTest {

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void pojoToJsonString() throws JsonProcessingException {
        Person person = new Person();
        person.setName("Ayang");
        person.setAge(18);
        person.setSkillList(Arrays.asList("java", "c++"));

        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);
        String expectedJson = "{\"name\":\"Ayang\",\"age\":18,\"skillList\":[\"java\",\"c++\"]}";
        Assertions.assertEquals(json, expectedJson);
    }
}
// 输出的 JSON 字符串:
// {"name":"Ayang","age":18,"skillList":["java","c++"]}

4.2 Jackson JSON 反序列化

将Json字符串反序列化为Java对象(Person类)

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class PersonTest01 {

    ObjectMapper objectMapper = new ObjectMapper();
    @Test
    public void jsonStringToPojo() throws JsonProcessingException {
        String expectedJson = "{\"name\":\"Ayang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
        // readValue方法的输入来源可以是很多种:文件/输入数据(字节数组、输入流等)
        Person person = objectMapper.readValue(expectedJson, Person.class);
        System.out.println(person);
        Assertions.assertEquals(person.getName(),"Ayang");
        Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]");
    }
}
// 输出结果
// Person(name=Ayang, age=27, skillList=[java, c++])

4.3 JSON 转 List

上面演示 JSON 字符串都是单个对象的,如果 JSON 是一个对象列表那么使用 Jackson 该怎么处理呢? 从 PersonList.json文件读取数据 转换成 List<Person>

json 复制代码
[
  {
    "name": "aLang",
    "age": 27,
    "skillList": [
      "java",
      "c++"
    ]
  },
  {
    "name": "darcy",
    "age": 26,
    "skillList": [
      "go",
      "rust"
    ]
  }
]

具体实现:

java 复制代码
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class PersonTest02 {

    ObjectMapper objectMapper = new ObjectMapper();
    @Test
    public void jsonStringToPojo() throws IOException {
        File file = new File("src/PersonList.json");
        List<Person> personList = objectMapper.readValue(file, new TypeReference<List<Person>>() {});
        for (Person person : personList) {
            System.out.println(person);
        }
        Assertions.assertEquals(personList.size(), 2);
        Assertions.assertEquals(personList.get(0).getName(), "aLang");
        Assertions.assertEquals(personList.get(1).getName(), "darcy");
    }
}
// 输出结果
//Person(name=aLang, age=27, skillList=[java, c++])
//Person(name=darcy, age=26, skillList=[go, rust])

4.4 JSON 转 Map

使用 Jackson 把 JSON 文本转成 Map 对象。

java 复制代码
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Map;

public class PersonTest03 {
    ObjectMapper objectMapper = new ObjectMapper();
    @Test
    public void jsonStringToPojo() throws IOException {
        String expectedJson = "{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
        Map<String, Object> employeeMap = objectMapper.readValue(expectedJson, new TypeReference<Map>() {});
        System.out.println(employeeMap.getClass());
        for (Map.Entry<String, Object> entry : employeeMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        Assertions.assertEquals(employeeMap.get("name"), "aLang");
    }
}
// 输出结果
/*
class java.util.LinkedHashMap
name:aLang
age:27
skillList:[java, c++]
*/

4.5 Jackson 忽略字段

如果在进行 JSON 转 Java 对象时,JSON 中出现了 Java 类中不存在的属性,那么在转换时会遇到 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 异常。使用 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 可以忽略不存在的属性。

java 复制代码
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.IOException;

public class PersonTest04 {

    ObjectMapper objectMapper = new ObjectMapper();
    @Test
    public void jsonStringToPojo() throws IOException {
        String json = "{\"yyy\":\"xxx\",\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        Person person = objectMapper.readValue(json, Person.class);
        System.out.printf(person.toString());
        Assertions.assertEquals(person.getName(), "aLang");
        Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]");
    }
}
//输出结果
// Person(name=aLang, age=27, skillList=[java, c++])

4.6 Jackson 日期格式化

在 Java 8 之前我们通常使用 java.util.Date 类来处理时间,但是在 Java 8 发布时引入了新的时间类 java.time.LocalDateTime. 这两者在 Jackson 中的处理略有不同。

java 复制代码
// 创建订单Order对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
    private Integer id;
    private Date createTime;
    private LocalDateTime updateTime;
}
4.6.1 Date类型的序列化与反序列化
java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Date;

public class DateTransform {

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void dateInPojoToJson() throws JsonProcessingException {
        Order order = new Order(1, new Date(), null);
        // 序列化为json
        String json = objectMapper.writeValueAsString(order);
        System.out.println(json);
        //反序列化为Order对象  
        order = objectMapper.readValue(json, Order.class);
        System.out.println(order.toString());
        Assertions.assertEquals(order.getId(), 1);
    }
}
/* 输出结果:
{"id":1,"createTime":1712729115179,"updateTime":null}
Order(id=1, createTime=Wed Apr 10 14:05:15 CST 2024, updateTime=null)
*/

可以看到正常的进行了 JSON 的序列化与反序列化,但是 JSON 中的时间是一个时间戳格式,可能不是我们想要的。

4.6.2 LocalDateTime类型的序列化与反序列化
java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.Date;

public class OrderTest {
    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void testPojoToJson() throws JsonProcessingException {
        Order order = new Order(1, new Date(), LocalDateTime.now());
        String json = objectMapper.writeValueAsString(order);
        System.out.println(json);

        order = objectMapper.readValue(json, Order.class);
        System.out.println(order.toString());

        Assertions.assertEquals(order.getId(), 1);
    }
}

运行报错:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type java.time.LocalDateTime not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.study.jackson.Order["updateTime"])

添加对应的依赖:

java 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.3</version>
</dependency>

添加依赖后的代码为:

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.Date;

public class OrderTest {
    // 通过findAndRegisterModules注册依赖
    ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();

    @Test
    public void testPojoToJson() throws JsonProcessingException {
        Order order = new Order(1, new Date(), LocalDateTime.now());
        String json = objectMapper.writeValueAsString(order);
        System.out.println(json);

        order = objectMapper.readValue(json, Order.class);
        System.out.println(order.toString());

        Assertions.assertEquals(order.getId(), 1);
    }
}
/* 输出结果:
{"id":1,"createTime":1712729605162,"updateTime":[2024,4,10,14,13,25,166000000]}
Order(id=1, createTime=Wed Apr 10 14:13:25 CST 2024, updateTime=2024-04-10T14:13:25.166)
*/
4.6.3 时间格式化

通过在字段上使用注解 @JsonFormat 来自定义时间格式。

java 复制代码
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order1 {
    private Integer id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
    private Date createTime;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
    private LocalDateTime updateTime;
}
java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.Date;

public class OrderTest01 {
    ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
    @Test
    public void testPojoToJson() throws JsonProcessingException {
        Order1 order = new Order1(1, new Date(), LocalDateTime.now());
        String json = objectMapper.writeValueAsString(order);
        System.out.println(json);

        order = objectMapper.readValue(json, Order1.class);
        System.out.println(order);
        Assertions.assertEquals(order.getId(),1);
    }
}
/*
输出结果:
{"id":1,"createTime":"2024-04-10 14:22:17","updateTime":"2024-04-10 14:22:17"}
Order1(id=1, createTime=Wed Apr 10 14:22:17 CST 2024, updateTime=2024-04-10T14:22:17)
*/

5.总结

  • Jackson 是 Java 中比较流量的 JSON 处理库之一,它是 Spring 的默认 JSON 工具。
  • Jackson 主要有三个模块组成,Streaming API 、Annotations 和 Data Binding 。
  • Jackson 中的 ObjectMapper 类十分强大,可以进行 JSON 相关处理,同时可以结合注释以及配置进行自定义转换逻辑。
  • Jackson 扩展性很好,如 CSV、XML、YAML 格式处理都对 Jackson 有相应的适配等。
相关推荐
爱编码的程序员1 天前
python 处理json、excel、然后将内容转化为DSL语句,适用于数据处理(实用版)
人工智能·python·ai·json·excel·数据处理·dsl
wtsolutions1 天前
免费MCP: JSON 转 Excel MCP
json·excel·api·csv·mcp·wtsolutions
杨DaB1 天前
【项目实践】在系统接入天气api,根据当前天气提醒,做好plan
java·后端·spring·ajax·json·mvc
hqxstudying2 天前
前后端交流
java·css·后端·html·json
Vic101014 天前
Hutool 的完整 JSON 工具类示例
开发语言·json
电商数据girl4 天前
如何利用API接口与网页爬虫协同进行电商平台商品数据采集?
大数据·开发语言·人工智能·python·django·json
拷斤锟4 天前
使用Excel解析从OData API获取到的JSON数据
数据库·json·excel
有育哥无奔波5 天前
是采用示例模板,还是采用json的结构化数据,哪种方式会让llm的输出更加稳定?
json
小小李程序员6 天前
JSON.parse解析大整数踩坑
开发语言·javascript·json
西哥写代码7 天前
基于dcmtk的dicom工具 第九章 以json文件或sqlite为数据源的worklist服务(附工程源码)
sqlite·json·mfc·dcmtk·worklist