目录

  • `JSON` 简述
  • `Jackson` 介绍
  • `Jackson` 的 `Maven` 依赖
  • `ObjectMapper` 对象映射器
  • `Jackson JSON` 的基本操作
    • `Jackson JSON` 的序列化
    • `Jackson JSON` 的反序列化
    • `JSON` 转 `List`
    • `JSON` 转 `Map`
    • `Jackson` 的忽略字段
    • `Jackson` 的日期格式化
      • `Date` 类型
      • `LocalDateTime` 类型
      • 时间格式化
  • `Jackson` 的常用注解
    • `@JsonIgnore`
    • `@JsonGetter`
    • `@JsonSetter`
    • `@JsonAnySetter`
    • `@JsonAnyGetter`
  • `Jackson` 总结

JSON 简述

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

JSONJavaScript 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 介绍

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

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

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

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

JacksonMaven 依赖

在使用 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 对象映射器

ObjectMapperJackson 库中最常用的一个类,使用它可以进行 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 类,定义三个属性,名称、年龄以及技能

@Data
public class Person {private String name;private Integer age;private List<String> skillList;
}

Java 对象转换成 JSON 字符串

public class PersonTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid 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 的反序列化

public class PersonTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid 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++])

JSONList

上面演示 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])

JSONMap

JSONMap 在我们没有一个对象的 Java 对象时十分实用,下面演示如何使用 JacksonJSON 文本转成 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 的忽略字段

如果在进行 JSONJava 对象时,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 {// UnrecognizedPropertyExceptionString 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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {private Integer id;private Date createTime;private LocalDateTime updateTime;
}

Date 类型

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

class OrderTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid 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 转换会遇到报错

class OrderTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid 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() 方法来注册依赖

class OrderTest {ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();@Testvoid 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":1658321191562,"updateTime":[2022,7,20,20,46,31,567000000]}
Order(id=1, createTime=Wed Jul 20 20:46:31 CST 2022, updateTime=2022-07-20T20:46:31.567)

时间格式化

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {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;
}

再次运行上面的列子可以得到时间格式化后的 JSON 字符串

{"id":1,"createTime":"2022-07-20 20:49:46","updateTime":"2022-07-20 20:49:46"}
Order(id=1, createTime=Wed Jul 20 20:49:46 CST 2022, updateTime=2022-07-20T20:49:46)

Jackson 的常用注解

@JsonIgnore

使用 @JsonIgnore 可以忽略某个 Java 对象中的属性,它将不参与 JSON 的序列化与反序列化

@Data
public class Cat {private String name;@JsonIgnoreprivate Integer age;
}

编写单元测试类

class CatTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid testPojoToJson() throws JsonProcessingException {Cat cat = new Cat();cat.setName("Tom");cat.setAge(2);String json = objectMapper.writeValueAsString(cat);System.out.println(json);Assertions.assertEquals(json, "{\"name\":\"Tom\"}");cat = objectMapper.readValue(json, Cat.class);Assertions.assertEquals(cat.getName(), "Tom");Assertions.assertEquals(cat.getAge(), null);}
}

输出结果中 age 属性为 null

{"name":"Tom"}

@JsonGetter

使用 @JsonGetter 可以在对 Java 对象进行 JSON 序列化时自定义属性名称

@Data
public class Cat {private String name;private Integer age;@JsonGetter(value = "catName")public String getName() {return name;}
}

编写单元测试类进行测试

class CatTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid testPojoToJson2() throws JsonProcessingException {Cat cat = new Cat();cat.setName("Tom");cat.setAge(2);String json = objectMapper.writeValueAsString(cat);System.out.println(json);Assertions.assertEquals(json, "{\"age\":2,\"catName\":\"Tom\"}");}
}

输出结果,name 已经设置成了 catName

{"age":2,"catName":"Tom"}

@JsonSetter

使用 @JsonSetter 可以在对 JSON 进行反序列化时设置 JSON 中的 keyJava 属性的映射关系

@Data
public class Cat {@JsonSetter(value = "catName")private String name;private Integer age;@JsonGetter(value = "catName")public String getName() {return name;}
}

编写单元测试类进行测试

class CatTest {ObjectMapper objectMapper = new ObjectMapper();@Testvoid testPojoToJson2() throws JsonProcessingException {String json = "{\"age\":2,\"catName\":\"Tom\"}";Cat cat = objectMapper.readValue(json, Cat.class);System.out.println(cat.toString());Assertions.assertEquals(cat.getName(), "Tom");}
}

输出结果

Cat(name=Tom, age=2)

@JsonAnySetter

使用 @JsonAnySetter 可以在对 JSON 进行反序列化时,对所有在 Java 对象中不存在的属性进行逻辑处理,下面的代码演示把不存在的属性存放到一个 Map 集合中

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private Integer age;private Map<String, Object> diyMap = new HashMap<>();@JsonAnySetterpublic void otherField(String key, String value) {this.diyMap.put(key, value);}
}

编写单元测试用例

class StudentTest {private ObjectMapper objectMapper = new ObjectMapper();@Testvoid testJsonToPojo() throws JsonProcessingException {Map<String, Object> map = new HashMap<>();map.put("name", "aLang");map.put("age", 18);map.put("skill", "java");String json = objectMapper.writeValueAsString(map);System.out.println(json);Student student = objectMapper.readValue(json, Student.class);System.out.println(student);Assertions.assertEquals(student.getDiyMap().get("skill"), "java");}
}

输出结果中可以看到 JSON 中的 skill 属性因为不在 JavaStudent 中,所以被放到了 diyMap 集合

{"skill":"java","name":"aLang","age":18}
Student(name=aLang, age=18, diyMap={skill=java})

@JsonAnyGetter

使用 @JsonAnyGetter 可以在对 Java 对象进行序列化时,使其中的 Map 集合作为 JSON 中属性的来源

@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Student {@Getter@Setterprivate String name;@Getter@Setterprivate Integer age;@JsonAnyGetterprivate Map<String, Object> initMap = new HashMap() {{put("a", 111);put("b", 222);put("c", 333);}};
}

编写单元测试用例

class StudentTest {private ObjectMapper objectMapper = new ObjectMapper();@Testvoid testPojoToJsonTest() throws JsonProcessingException {Student student = new Student();student.setName("aLang");student.setAge(20);String json = objectMapper.writeValueAsString(student);System.out.println(json);Assertions.assertEquals(json,"{\"name\":\"aLang\",\"age\":20,\"a\":111,\"b\":222,\"c\":333}");}
}

输出结果

{"name":"aLang","age":20,"a":111,"b":222,"c":333}

Jackson 总结

  • JacksonJava 中比较流量的 JSON 处理库之一,它是 Spring 的默认 JSON 工具
  • Jackson 主要有三个模块组成,Streaming API 、AnnotationsData Binding
  • Jackson 中的 ObjectMapper 类十分强大,可以进行 JSON 相关处理,同时可以结合注释以及配置进行自定义转换逻辑。
  • Jackson 扩展性很好,如 CSV、XML、YAML 格式处理都对 Jackson 有相应的适配等

Jackson解析JSON详细教程相关推荐

  1. Jackson 解析 JSON 详细教程

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

  2. Jackson解析JSON数据教程

    Json解析-Jackson使用教程 日常求赞,感谢老板. 欢迎关注公众号:其实是白羊.干货持续更新中- 一.JSON解析 我这里指的解析是:JSON和JavaObject之间的序列化和反序列化. 如 ...

  3. JSON(json)详细教程

    JSON详细教程 一.什么是JSON? 二.JSON的语法规则 具体规则: 1.JSON名称/值对 2.JSON的值的类型 1. 数字(整数或者浮点数) 2. 字符串(在双引号中) 3. 逻辑值(tr ...

  4. 记一次FastJSON和Jackson解析json时遇到的中括号问题

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jadyer/article/details/24395015 完整版见https://jadyer. ...

  5. android jackson 解析json字符串,一文搞定Jackson解析JSON数据

    Json解析-Jackson使用教程 日常求赞,感谢老板. 一.JSON解析 我这里指的解析是:JSON和JavaObject之间的序列化和反序列化. 如果你的项目进行了前后端分离,那你一定使用过JS ...

  6. android jackson 解析json字符串,android:json解析的两个工具:Gson和Jackson的使用小样例...

    1.简单介绍 json是android与server通信过程中经常使用的数据格式,比如.例如以下是一个json格式的字符串: {"address":"Nanjing&qu ...

  7. 使用jackson解析json数据详讲

    Java操作json数据 json 简介 概念 JSON:JavaScript Object Notations,即javaScript的对象表示法,是javaScript语法的一个子集,相当于jav ...

  8. jackson 解析json问题

    1.json串中有key为A,但指定转换的mybean中未定义属性A,会抛异常.处理:mapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, fals ...

  9. 使用Jackson解析JSON

    注: http://justcode.ikeepstudying.com/2018/01/java-%E4%BD%BF%E7%94%A8jackson%E8%A7%A3%E6%9E%90json-%E ...

最新文章

  1. (12)调用门阶段测试
  2. LeetCode 519. 随机翻转矩阵(哈希)
  3. Java接口、implements关键字、接口中抽象方法,默认方法,静态方法,私有方法,常量、final关键字
  4. POP3启用LDAP实现自动加载邮件通讯录的过程
  5. 有趣 的java代码_[分享]几段有趣的JAVA代码
  6. 百度文库免费复制文字_百度文库免费下载Word全方案
  7. 关于linux系统安装zabbix报错的解决方案
  8. 如何拆分PDF文件,PDF如何拆分页面
  9. 南京邮电大学汇编——实验一:汇编语言语法练习与代码转换
  10. 怎么看263邮箱的服务器信息,263邮箱真的不能用,刚刚上了一当,劝大家务必注意...
  11. mysql端口3309_为mysql添加端口号为3309的实例:
  12. 2017百度AI开发者大会召开,智能云计算分论坛聚焦ABC
  13. HTML+CSS学习笔记(篇幅较大)
  14. wps 写论文时 参考文献的横线怎么消除
  15. Java——接口与实现类
  16. 取消iphone 自动更新提示
  17. Java序列化三连问,是什么?为什么需要?如何实现?
  18. 从10个角度来检测自己是不是一个合格的前端工程师,这些要求你都达到了吗?
  19. typescript将ES5转ES6
  20. 千克与磅之间的转换 Exercise05_05

热门文章

  1. 动手学深度学习(二十二)——GoogLeNet:CNN经典模型(五)
  2. HBU训练营【动态规划DP】——兔子跳楼梯 (20分)
  3. win7系统损坏无法开机_win7系统网络适配器无法启动怎么办
  4. 如何看待:Oracle Java SE 8 发行版更新 ? --- 变向激励学习 JDK 10 吗?
  5. snap安装nextcloud关键点
  6. R语言基础入门(学习笔记通俗易懂版)
  7. 单片机利用Proteus进行仿真点亮一个LED灯(C语言和汇编语言)
  8. 基于javaweb+mysql的医药信息管理系统(java+SSM+HTML+easyui+mysql)
  9. 区块链中的Merkle树
  10. Java开源GIS系统