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 有相应的适配等。
相关推荐
nbsaas-boot17 小时前
探索 JSON 数据在关系型数据库中的应用:MySQL 与 SQL Server 的对比
数据库·mysql·json
疯一样的码农19 小时前
Jackson 的@JsonRawValue
json
Web打印1 天前
web打印插件 HttpPrinter 使用半年评测
javascript·json·firefox·jquery·html5
手心里的白日梦1 天前
网络计算器的实现:TCP、守护进程、Json、序列化与反序列化
网络·tcp/ip·json
chenchihwen1 天前
数据分析时的json to excel 转换的好用小工具
数据分析·json·excel
子燕若水1 天前
简要解释JSON Schema
前端·html·json
Json_181790144801 天前
淘系商品评论json数据示例参考,API接口系列
大数据·json·api
慕羽★2 天前
详细介绍如何使用rapidjson读取json文件
linux·c++·windows·json·file·param·rapidjson
轻口味2 天前
配置TypeScript:tsconfig.json详解
ubuntu·typescript·json
zybishe2 天前
免费送源码:Java+ssm++MVC+HTML+CSS+MySQL springboot 社区医院信息管理系统的设计与实现 计算机毕业设计原创定制
java·hadoop·sql·zookeeper·html·json·mvc