jackson解析json详细教程(代码片段)

程序猿阿朗 程序猿阿朗     2022-11-30     411

关键词:

点赞再看,动力无限。 微信搜「 程序猿阿朗 」。

本文 Github.com/niumoo/JavaNotes未读代码博客 已经收录,有很多知识点和系列文章。

JSON 对于开发者并不陌生,如今的 WEB 服务、移动应用、甚至物联网大多都是以 JSON 作为数据交换的格式。学习 JSON 格式的操作工具对开发者来说是必不可少的。这篇文章将介绍如何使用 Jackson 开源工具库对 JSON 进行常见操作。

JSON 介绍

什么是 JSON ?JSON 是 ”JavaScript Object Notation“ 的缩写,JSON 是一种基于文本的格式,可以把它理解为是一个结构化的数据,这个结构化数据中可以包含键值映射、嵌套对象以及数组等信息。


  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "color": "gold",
  "null": null,
  "number": 123,
  "object": 
    "a": "b",
    "c": "d"
  ,
  "string": "www.wdbyte.com"

Jackson 介绍

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 等。

Jackson Maven 依赖

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

  • com.fasterxml.jackson.core:jackson-annotations
  • com.fasterxml.jackson.core:jackson-core
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>

为了方便这篇文章后续的代码演示,我们同时引入 Junit 进行单元测试和 Lombok 以减少 Get/Set 的代码编写。

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>

ObjectMapper 对象映射器

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

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

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

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

Jackson JSON 基本操作

Jackson 作为一个 Java 中的 JSON 工具库,处理 JSON 字符串和 Java 对象是它最基本最常用的功能,下面通过一些例子来演示其中的用法。

Jackson JSON 序列化

编写一个 Person 类,定义三个属性,名称、年龄以及技能。

/**
 * @author https://www.wdbyte.com
 */
@Data
public class Person 
    private String name;
    private Integer age;
    private List<String> skillList;

将 Java 对象转换成 JSON 字符串。

import java.util.Arrays;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author https://www.wdbyte.com
 */
class PersonTest 

    ObjectMapper objectMapper = new ObjectMapper();

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

        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);
        String expectedJson = "\\"name\\":\\"aLng\\",\\"age\\":27,\\"skillList\\":[\\"java\\",\\"c++\\"]";
        Assertions.assertEquals(json, expectedJson);
    

输出的 JSON 字符串:

"name":"aLng","age":27,"skillList":["java","c++"]

Jackson 甚至可以直接把序列化后的 JSON 字符串写入文件或者读取成字节数组。

mapper.writeValue(new File("result.json"), myResultObject);
// 或者
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// 或者
String jsonString = mapper.writeValueAsString(myResultObject);

Jackson JSON 反序列化

直接贴出代码:

package com.wdbyte.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author https://www.wdbyte.com
 */
class PersonTest 

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    void jsonStringToPojo() throws JsonProcessingException 
        String expectedJson = "\\"name\\":\\"aLang\\",\\"age\\":27,\\"skillList\\":[\\"java\\",\\"c++\\"]";
        Person person = objectMapper.readValue(expectedJson, Person.class);
        System.out.println(person);
        Assertions.assertEquals(person.getName(), "aLang");
        Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]");
    

输出结果:

Person(name=aLang, age=27, skillList=[java, c++])

上面的例子演示了如何使用 Jackson 把一个 JSON 字符串反序列化成 Java 对象,其实 Jackson 对文件中的 JSON 字符串、字节形式的 JSON 字符串反序列化同样简单。

比如先准备了一个 JSON 内容文件 Person.json。


  "name": "aLang",
  "age": 27,
  "skillList": [
    "java",
    "c++"
  ]

下面进行读取转换。

ObjectMapper objectMapper = new ObjectMapper();

@Test
void testJsonFilePojo() throws IOException 
    File file = new File("src/Person.json");
    Person person = objectMapper.readValue(file, Person.class);
  	// 或者
    // person = mapper.readValue(new URL("http://some.com/api/entry.json"), MyValue.class);
    System.out.println(person);
    Assertions.assertEquals(person.getName(), "aLang");
    Assertions.assertEquals(person.getSkillList().toString(), "[java, c++]");

同样输出了 Person 内容。

Person(name=aLang, age=27, skillList=[java, c++])

JSON 转 List

上面演示 JSON 字符串都是单个对象的,如果 JSON 是一个对象列表那么使用 Jackson 该怎么处理呢?

已经存在一个文件 PersonList.json.

[
  
    "name": "aLang",
    "age": 27,
    "skillList": [
      "java",
      "c++"
    ]
  ,
  
    "name": "darcy",
    "age": 26,
    "skillList": [
      "go",
      "rust"
    ]
  
]

读取它然后转换成 List<Person>

ObjectMapper objectMapper = new ObjectMapper();

@Test
void fileToPojoList() throws IOException 
    File file = new File("src/EmployeeList.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])

JSON 转 Map

JSON 转 Map 在我们没有一个对象的 Java 对象时十分实用,下面演示如何使用 Jackson 把 JSON 文本转成 Map 对象。

ObjectMapper objectMapper = new ObjectMapper();

@Test
void jsonStringToMap() 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 (Entry<String, Object> entry : employeeMap.entrySet()) 
        System.out.println(entry.getKey() + ":" + entry.getValue());
    
    Assertions.assertEquals(employeeMap.get("name"), "aLang");

可以看到 Map 的输出结果:

class java.util.LinkedHashMap
name:aLang
age:27
skillList:[java, c++]

Jackson 忽略字段

如果在进行 JSON 转 Java 对象时,JSON 中出现了 Java 类中不存在的属性,那么在转换时会遇到 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 异常。

使用 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 可以忽略不存在的属性。

ObjectMapper objectMapper = new ObjectMapper();

@Test
void jsonStringToPojoIgnoreProperties() throws IOException 
    // UnrecognizedPropertyException
    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++])

Jackson 日期格式化

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

先创建一个有两种时间类型属性的 Order 类。

package com.wdbyte.jackson;

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

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author https://www.wdbyte.com
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order 
  
    private Integer id;

    private Date createTime;

    private LocalDateTime updateTime;


Date 类型

下面我们新建一个测试用例来测试两种时间类型的 JSON 转换。

package com.wdbyte.jackson;

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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author https://www.wdbyte.com
 */
class OrderTest 

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    void testPojoToJson0() throws JsonProcessingException 
        Order order = new Order(1, new Date(), null);
        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);
    


在这个测试代码中,我们只初始化了 Date 类型的时间,下面是输出的结果:

"id":1,"createTime":1658320852395,"updateTime":null
Order(id=1, createTime=Wed Jul 20 20:40:52 CST 2022, updateTime=null)

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

LocalDateTime 类型

为什么没有设置 LocalDateTime 类型的时间呢?因为默认情况下进行 LocalDateTime 类的 JSON 转换会遇到报错。

/**
 * @author https://www.wdbyte.com
 */
class OrderTest 

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    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.wdbyte.jackson.Order["updateTime"])

这里我们需要添加相应的数据绑定支持包。

添加依赖:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.3</version>
</dependency>

然后在定义 ObjectMapper 时通过 findAndRegisterModules() 方法来注册依赖。

import 查看详情  

《springboot篇》26.springboot整合jackson超详细教程(附jackson工具类)(代码片段)

...的内容)👨‍💻本文简述:本文讲一下Jackson常见用法,超级详细。👨‍💻上一篇文章:《SpringBoot篇》25.SpringBoot整合ActiveMQ👨‍💻有任何问题,都可以私聊我,我能帮得上的一定... 查看详情

json处理——fastjsonjacksongson详细使用(代码片段)

...对象2.3JSON对象、JSON数组的其他操作2.4JSONPath解析JSON三、Jackson使用3.1ObjectMapper基本使用3.2ObjectMapper相关配置及异常场景3.3注解方式配置四、Gson使用一、基本介绍JSON:一种轻量级的数据交换格式。JSON的数据格式比较简单,... 查看详情

json11详细使用教程,持续更新!(代码片段)

...,持续更新jsonjson11基本使用一些json11的具体操作json11解析数组,并基于范围循环遍历参考资料jsonJSON的全称是”JavaScriptObjectNotation”,意思是JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据... 查看详情

@requestbodyjackson解析复杂的传入值的一个坑;jackson解析迭代数组;jackson多重数组;jakson数组(代码片段)

一、实际开发的一个问题。   传入一个json数组,数组中还嵌套数组,运用springboot+Jpa框架,@RequestBody注解传入数据   Controller1@ApiOperation(value="添加订单",notes="添加订单",httpMethod="POST")2@RequestMapping("/addOrde 查看详情

java示例代码_在Jackson中将JSON字符串解析为JsonNode

java示例代码_在Jackson中将JSON字符串解析为JsonNode 查看详情

springboot修改配置json解析(代码片段)

在Springboot中默认的JSON解析框架是jackson定制或使用fastjson需要替换默认的json转换器的方法。一、(1)实现WebMvcConfigurer(2)覆盖方法configureMessageConverters@ConfigurationpublicclassWebMVCConfigimplementsWeb 查看详情

#jackson学习使用(代码片段)

Jackson学习使用Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。Jackson所依赖的jar包较少,简单易用并且性能也要相对高些,并且Jackson社区... 查看详情

引入jackson-dataformat-xml后,默认响应结果是json还是xml?(代码片段)

...问题。引用XML解析包<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><arti 查看详情

springboot处理json数据(代码片段)

...Boot的Web应用中,内置JSON数据解析功能,默认使用Jackson自动解析,不需要加载Jackson依赖包,当控制器返回一个Java对象或者集合数据时,SpringBoot自动将其转换为Json格式数据,使用起来方便简洁。SpringBoot处... 查看详情

jackson(代码片段)

一,Jackson使用示例第1步:创建ObjectMapper对象。创建ObjectMapper对象。它是一个可重复使用的对象。ObjectMappermapper=newObjectMapper();第2步:反序列化JSON到对象。从JSON对象使用readValue()方法来获取。通过JSON字符串和对象类型作为参数JSON... 查看详情

mybatis(jackson:controller返回json数据(集合日期日期工具类)fastjson)(代码片段)

1、Jackson的使用(1)概念Jackson是目前比较好的json解析工具,还有阿里巴巴的fastjson等等(2)导入依赖<!--https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind--><dependency><groupId>com.fasterxml.jackson.core</groupId>... 查看详情

java:json解析利器jackson

Java:JSON解析利器JackSonJackSon基础1.Maven项目引入<!--https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl--><dependency><groupId>org.codehaus.jackson</groupId><ar 查看详情

jason有一个字符串字段为null,因此jackson解析器抛出错误(代码片段)

RESTAPI返回的JSON字符串为“Id”:1,“Name”:“Test1”,“Description”:“Test1description”,“ShowInMainScreen”:true,“CREATEDATE”:“2017-12-09T09:55:37”,“LASTUPDATEDATE”:“2017-12-09T09:55:37”,“Traini 查看详情

小白教程—最详细java循环结构解析之for循环(代码片段)

...录循环结构的分类for循环基本语法for循环的执行顺序实例解析嵌套for循环基本语法实例解析循环结构的分类在Java中,循环结构一共分为三类:1.for循环2.while循环3.do-while循环for循环for循环是被使用最广泛的循环,使用计数... 查看详情

引入jackson-dataformat-xml后,默认响应结果是json还是xml?(代码片段)

...问题。引用XML解析包<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.0</version></dependency>定义测试类定义一个测试Controller,添加一个方法:&... 查看详情

java下利用jackson进行json解析和序列化

Java下常见的Json类库有Gson、JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行JSON和Java对象转换,下面给出一些Jackson的JSON操作方法。一、准备工作首先去官网下载Jackson工具包,下载地址http://wiki.fasterxml.com/... 查看详情

java下利用jackson进行json解析和序列化

Java下常见的Json类库有Gson、JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行JSON和Java对象转换,下面给出一些Jackson的JSON操作方法。一、准备工作首先去官网下载Jackson工具包,下载地址http://wiki.fasterxml.com/... 查看详情