Jackson ObjectMapper使用和常用注解

  • 一、前言
    • 1. 引入Jackson
  • 二、ObjectMapper
    • 1. 创建ObjectMapper
    • 2. 序列化
      • 2.1 Java对象 转 JSON
      • 2.2 Java List 转 JSON
      • 2.3 Java Map 转 JSON
      • 2.4 美化输出格式
      • 2.5 序列化结果写文件
    • 3. 反序列化
      • 3.1 JSON 转 Java对象
      • 3.2 JSON 转 Java List
      • 3.3 JSON 转 Java Map
      • 3.4 JSON File 转 Java对象
      • 3.5 JSON Reader 转 Java对象
      • 3.6 JSON InputStream 转 Java对象
      • 3.7 JSON Byte Array 转 Java对象
      • 3.8 JSON via URL 转 Java对象
  • 三、Jackson注解
    • 1. 序列化/反序列化都生效注解
      • 1.1 @JsonIgnore
      • 1.2 @JsonIgnoreProperties
      • 1.3 @JsonIgnoreType
      • 1.4 @JsonProperty
      • 1.5 @JsonAnyGetter和@JsonAnySetter
        • 1.5.1 非嵌套的otherAttributes
        • 1.5.2 嵌套的otherAttributes
    • 2. 仅序列化时生效注解
      • 2.1 @JsonFormat
      • 2.2 @JsonInclude
      • 2.3 @JsonPropertyOrder
      • 2.4 @JsonView
      • 2.5 @JsonRawValue
  • 四、结语

SpringBoot教程(11) Jackson中的JsonNode,ObjectNode,ArrayNode使用和区别
SpringBoot教程(12) Jackson中的JsonGenerator案例

一、前言

Jackson和Fastjson都是比较出名的JSON解析库,SpringMVC默认使用的是Jackson,而且在企业项目中也大多使用的是Jackson,感觉还是很有必要熟悉Jackson的基本使用的。

1. 引入Jackson

如果只是简单的Java代码,不使用Spring Boot的话,直接引入Jackson。

        <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.1</version></dependency>

如果是使用了SpringBoot的项目,引入spring-boot-starter-web就会自动引入Jackson。

     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

二、ObjectMapper

我们使用Jackson等工具时,最常见的场景就是JSON的序列化和反序列化。而Jackson最常用的的就是ObjectMapper, 它提供了丰富的方法。

1. 创建ObjectMapper

如果是普通Java项目,则new一个ObjectMapper。

private ObjectMapper mapper = new ObjectMapper();

如果是使用Spring项目,则自动注入ObjectMapper。

@Autowired
private ObjectMapper objectMapper;

2. 序列化

假设有一个Java类:Student。

2.1 Java对象 转 JSON

Student student = getStudent();
String studentStr = mapper.writeValueAsString(student);

2.2 Java List 转 JSON

List<Student> studentList= getStudentList();
String studentListStr = mapper.writeValueAsString(studentList);

2.3 Java Map 转 JSON

Map<String, Object> studentMap = new HashMap<>();
studentMap.put("id", "1");
studentMap.put("name", "亚瑟");
studentMap.put("age", 33);String studentJsonStr = mapper.writeValueAsString(studentMap);

2.4 美化输出格式

在调writeValueAsString之前先调writerWithDefaultPrettyPrinter

String studentStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);

2.5 序列化结果写文件

mapper.writeValue(new File(OBJECT_FILE_PATH_FOR_WRITE_FROM_SRC), student);

3. 反序列化

3.1 JSON 转 Java对象

String studentStr = getStudentString();
Student student = mapper.readValue(studentStr, Student.class);

3.2 JSON 转 Java List

List<Student> studentList1 = mapper.readValue(studentListStr , new TypeReference<>() {});
或者
List<Student> studentList2 = Arrays.asList(mapper.readValue(studentListStr, Student[].class));

3.3 JSON 转 Java Map

HashMap studentMap = mapper.readValue(studentStr, HashMap.class);

3.4 JSON File 转 Java对象

File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(file, Student.class);

3.5 JSON Reader 转 Java对象

File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Reader reader = new java.io.FileReader(file);
Student student = mapper.readValue(reader, Student.class);

3.6 JSON InputStream 转 Java对象

InputStream inputStream = new FileInputStream(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(inputStream, Student.class);

3.7 JSON Byte Array 转 Java对象

Student student = mapper.readValue(studentStr.getBytes(StandardCharsets.UTF_8), Student.class);

3.8 JSON via URL 转 Java对象

URL url = new URL("file:" + OBJECT_FILE_PATH_FROM_SRC);
Student student6 = mapper.readValue(url, Student.class);

三、Jackson注解

1. 序列化/反序列化都生效注解

1.1 @JsonIgnore

工作中一般会修饰Java类的属性上,无论序列化还是反序列化,Jackson都会忽略这个属性。
举个例子:@JsonIgnore修饰id属性

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonIgnore {@JsonIgnoreprivate String id;private String name;//注意得用Integer,而不能用intprivate Integer age;
}

序列化:

StudentTestForJsonIgnore stu = new StudentTestForJsonIgnore("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果: 忽略了id

{"name":"亚瑟","age":30}

反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30}";
StudentTestForJsonIgnore stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnore.class);
System.out.println(stu2.toString());

打印反序列化结果: 忽略了id

StudentTestForJsonIgnore(id=null, name=亚瑟, age=30)

1.2 @JsonIgnoreProperties

@JsonIgnoreProperties的作用和@JsonIgnore类似,但是@JsonIgnoreProperties修饰在Java类上,它可设置忽略多个属性,且可以设置ignoreUnknown = true,反序列化时,忽略在JSON中存在,但在Java类中不存在的字段,而不报异常。
举个例子:@JsonIgnoreProperties设置了"id", “age”,且设ignoreUnknown = true

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(value = {"id", "age"}, ignoreUnknown = true)
public class StudentTestForJsonIgnoreProperties {private String id;private String name;private Integer age;
}

序列化:

StudentTestForJsonIgnoreProperties stu = new StudentTestForJsonIgnoreProperties("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果: 忽略了"id", "age"这2个属性

{"name":"亚瑟"}

反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30, \"nickName\":\"Yase\"}";
StudentTestForJsonIgnoreProperties stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnoreProperties.class);
System.out.println(stu2.toString());

打印反序列化结果:

StudentTestForJsonIgnoreProperties(id=null, name=亚瑟, age=null)

1.3 @JsonIgnoreType

当其他类有该类作为属性时,该属性将被忽略。
举例:关于Student的类,添加了englishName属性。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonIgnoreType {private String id;private String name;private EnglishName englishName;private Integer age;
}

EnglishName 类定义如下,用@JsonIgnoreType修饰

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreType
public class EnglishName {public String firstName;public String lastName;
}

序列化:

StudentTestForJsonIgnoreType stu = new StudentTestForJsonIgnoreType("1", "亚瑟", new EnglishName("Ya", "SE"), 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果: 忽略了englishName属性

{"id":"1","name":"亚瑟","age":30}

反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30, \"englishName\":{\"firstName\":\"Ya\",\"lastName\":\"SE\"}}";
StudentTestForJsonIgnoreType stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnoreType.class);
System.out.println(stu2.toString());

打印反序列化结果:

StudentTestForJsonIgnoreType(id=1, name=亚瑟, englishName=null, age=30)

1.4 @JsonProperty

如果JSON中字段名和Java类中的属性名不一致时,可以用@JsonProperty修饰在属性上。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonProperty {private String id;@JsonProperty("studentName")private String name;private Integer age;
}

序列化:

StudentTestForJsonProperty stu = new StudentTestForJsonProperty("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果: studentName代替了name

{"id":"1","age":30,"studentName":"亚瑟"}

反序列化:

String stuFullStr = "{\"id\":\"1\",\"studentName\":\"亚瑟\",\"age\":30}";
StudentTestForJsonProperty stu2 = mapper.readValue(stuFullStr, StudentTestForJsonProperty.class);
System.out.println(stu2.toString());

打印反序列化结果: studentName的值赋值给了name属性

StudentTestForJsonProperty(id=1, name=亚瑟, age=30)

1.5 @JsonAnyGetter和@JsonAnySetter

@JsonAnyGetter
1.方法是非静态,没有参数的,方法名随意
2.方法返回值必须是Map类型
3.在一个实体类中仅仅用在一个方法上
4.序列化的时候json字段的key就是返回Map的key,value就是Map的value

@JsonAnySetter
1.用在非静态方法上,注解的方法必须有两个参数,第一个是json字段中的key,第二个是value,方法名随意
2.也可以用在Map对象属性上面,建议用在Map对象属性上面
3.反序列化的时候将对应不上的字段全部放到Map里面

1.5.1 非嵌套的otherAttributes

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonGetSet {private String id;private String name;private Integer age;private Map<String, Object> otherAttributes = new HashMap<>();@JsonAnyGetterpublic Map<String, Object> getOtherAttributes() {return this.otherAttributes;}@JsonAnySetterpublic void setOtherAttributes(String name, Object value) {this.otherAttributes.put(name, value);}
}
public static void main(String[] args) throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();Map<String, Object> otherAttributes = new HashMap<>();otherAttributes.put("what", "1");StudentTestForJsonGetSet stu = new StudentTestForJsonGetSet("1", "亚瑟", 30, otherAttributes);//序列化String stuStr = mapper.writeValueAsString(stu);System.out.println(stuStr);//反序列化String stuFullStr = "{\"id\":\"1\",\"studentName\":\"亚瑟\",\"age\":30,\"what\":\"1\"}";StudentTestForJsonGetSet stu2 = mapper.readValue(stuFullStr, StudentTestForJsonGetSet.class);System.out.println(stu2.toString());
}
{"id":"1","name":"亚瑟","age":30,"what":"1"}
StudentTestForJsonGetSet(id=1, name=null, age=30, otherAttributes={what=1, studentName=亚瑟})

1.5.2 嵌套的otherAttributes

如果otherAttributes接收嵌套的JSON结构,则Map的Value是LinkedHashMap类型。

先准备数据

ObjectMapper mapper = new ObjectMapper();Map<String, StudentTestForJsonGetSet> level2 = new HashMap<>();
StudentTestForJsonGetSet studentTestForJsonGetSet = new StudentTestForJsonGetSet();
studentTestForJsonGetSet.setId("1-1");
studentTestForJsonGetSet.setName("name-1-1");
studentTestForJsonGetSet.setAge(11);
level2.put("Key-1-1", studentTestForJsonGetSet);Map<String, Object> level1 = new HashMap<>();
level1.put("Key-1", level2);StudentTestForJsonGetSet stu = new StudentTestForJsonGetSet("1", "亚瑟", 30, level1);

序列化

String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);
{"id":"1","name":"亚瑟","age":30,"Key-1":{"Key-1-1":{"id":"1-1","name":"name-1-1","age":11}}}

反序列化

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30,\"Key-1\":{\"Key-1-1\":{\"id\":\"1-1\",\"name\":\"name-1-1\",\"age\":11}}}";
StudentTestForJsonGetSet stu2 = mapper.readValue(stuFullStr, StudentTestForJsonGetSet.class);
System.out.println(stu2.toString());

2. 仅序列化时生效注解

2.1 @JsonFormat

在序列化日期/时间值时指定格式。
下面@JsonFormat注解指定时间序列化后的格式。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonFormat {private String id;private String name;private Integer age;//默认情况下,Date序列化为自1970年1月1日以来的毫秒数(long类型)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date time;
}

序列化:

StudentTestForJsonFormat stu = new StudentTestForJsonFormat("1", "亚瑟", 30, new Date());
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果:

{"id":"1","name":"亚瑟","age":30,"time":"2022-03-28 17:21:26"}

反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30,\"time\":\"2022-03-07 18:39:12\"}";
StudentTestForJsonFormat stu2 = mapper.readValue(stuFullStr, StudentTestForJsonFormat.class);
System.out.println(stu2.toString());

打印反序列化结果:

StudentTestForJsonFormat(id=1, name=亚瑟, age=30, time=Mon Mar 07 18:39:12 CST 2022)

2.2 @JsonInclude

@JsonInclude是非常重要的且常用的注解,它可以修饰在类名上或者属性上,但是一般为了更加细粒度的控制,都修饰在属性上。

类型 说明
ALWAYS 这个是默认值,无论属性值是否为空,都参加序列化
NON_NULL 属性值不是NULL,才参加序列化
NON_ABSENT NON_NULL的增强版,Optional类型不是null,且isPresent()为true,才参加序列化。 实际开发中并不建议在实体类定义Optional类型的属性,如果你非要用,一定要赋默认值,比如Optional.empty()。
NON_EMPTY 属性值不是NULL,也不是"",如果是集合则isEmpty() = false,才参加序列化
NON_DEFAULT 属性值为缺省值时不序列化,比如int类型=0,String类型=null,这样不参加序列化。 实际开发中不要在实体类中用基础类型(如int,float),要用Integer代替int,具体原因参考阿里巴巴Java开发手册。
CUSTOM 结合注解JsonInclude.valueFilter和JsonInclude.contentFilter使用,这两个注解会指定一个Class,然后默认调用这个Class的空参构造方法,返回的对象eques属性值的话,序列化时就忽略。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonInclude {//哪怕是null,也会参与序列化@JsonIncludeprivate String id;//非NULL@JsonInclude(JsonInclude.Include.NON_NULL)private String name;//非NULL,非Optional.empty()@JsonInclude(JsonInclude.Include.NON_ABSENT)private Optional<String> nickName;@JsonInclude(JsonInclude.Include.NON_ABSENT)private Optional<String> nickName2;//非NULL,非“”,@JsonInclude(JsonInclude.Include.NON_EMPTY)private String englishName;//非NULL,集合isEmpty() = false@JsonInclude(JsonInclude.Include.NON_EMPTY)private List<CourseScore> courseScores;//属性值为缺省值时,不序列化@JsonInclude(JsonInclude.Include.NON_DEFAULT)private Integer age = 0;
}

序列化:

//注意要设置这个,用来支持Optional类型
mapper.registerModule(new Jdk8Module());StudentTestForJsonInclude stu = new StudentTestForJsonInclude();
stu.setId(null);
stu.setName(null);
stu.setNickName(Optional.ofNullable("亚瑟"));
stu.setNickName2(Optional.empty());
stu.setEnglishName("");
stu.setCourseScores(new ArrayList<>());
stu.setAge(0);//序列化
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果:

{"id":null,"nickName":"亚瑟"}

2.3 @JsonPropertyOrder

在序列化的时候自定义属性输出顺序
在类上修饰@JsonPropertyOrder,指定序列化后的JSON字段顺序为"age", “studentName”, “id”

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder(value = {"age", "studentName", "id"})
public class StudentTestForJsonPropertyOrder {private String id;@JsonProperty("studentName")private String name;private Integer age;
}

序列化:

StudentTestForJsonPropertyOrder stu = new StudentTestForJsonPropertyOrder("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

打印序列化结果:

{"age":30,"studentName":"亚瑟","id":"1"}

2.4 @JsonView

@JsonView是Jackson的一个很实用的注解,比如一个类的对象,要根据当前登录人的权限来分别序列化成他只能看到的字段。比如数据库里一条员工信息,老板和小组长的权限不同,应该看到的数据范围也不同。

public class Views {public static class NameOnly{};//NameAndAge 继承了 NameOnlypublic static class NameAndAge extends NameOnly{};
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonView {private String id;@JsonView(Views.NameOnly.class)private String name;@JsonView(Views.NameAndAge.class)private Integer age;
}

序列化:

StudentTestForJsonView stu = new StudentTestForJsonView("1", "亚瑟", 30);//序列化-NameOnly
String stuNameOnly = mapper.writerWithView(Views.NameOnly.class).writeValueAsString(stu);
System.out.println(stuNameOnly);//序列化-NameAndAge
String stuNameAndAge = mapper.writerWithView(Views.NameAndAge.class).writeValueAsString(stu);
System.out.println(stuNameAndAge);

打印序列化结果:

{"id":"1","name":"亚瑟"}
{"id":"1","name":"亚瑟","age":30}

2.5 @JsonRawValue

@JsonRawValue完全按照原样序列化属性的值

public class RawBean {public String name;@JsonRawValuepublic String json;
}
RawBean bean = new RawBean("My bean", "{\"attr\":false}");

打印序列化结果:

{"name":"My bean","json":{"attr":false}
}

而不是

{"name":"My bean","json":"{\"attr\":false}"
}

四、结语

本文总结了Jackson常用的序列化和反序列化方法,以及常用注解,但这些只是Jackson知识的很小一部分。Jackson还提供了丰富的配置项,JsonNode、ObjectNode还有JsonGenerator等功能。随着深入的学习,再一一记录。

SpringBoot教程(10) Jackson ObjectMapper使用和常用注解相关推荐

  1. SpringBoot教程(11) Jackson中的JsonNode,ObjectNode,ArrayNode使用和区别

    Jackson中的JsonNode,ObjectNode,ArrayNode使用和区别 一.前言 1. JsonNode作用 2. JsonNode VS ObjectNode 二.只读的JsonNo ...

  2. Spring常用注解的讲解

    转载,原文链接 作者:字母哥博客 本文出自:springboot深入浅出系列 文章目录 一.常用注解回顾 1.1 @RequestBody与@ResponseBody 1.2. @RequestMap ...

  3. SpringBoot教程(13) JUnit5详解 常用注解 BeforeEach BeforeAll ParameterizedTest RepeatedTest

    JUnit5详解 常用注解 BeforeEach BeforeAll ParameterizedTest RepeatedTest 一.前言 1. 引入test包 二.注解 三.测试案例 1. @Be ...

  4. 近100个Spring/SpringBoot常用注解汇总!

    作者 | Guide 来源 | JavaGuide(微信公众号) 毫不夸张地说,这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我 ...

  5. 视频教程- 19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合-Java

    19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有nod ...

  6. SpringBoot教程(十六) | SpringBoot集成swagger(全网最全)

    一. 接口文档概述 swagger是当下比较流行的实时接口文文档生成工具.接口文档是当前前后端分离项目中必不可少的工具,在前后端开发之前,后端要先出接口文档,前端根据接口文档来进行项目的开发,双方开发 ...

  7. [译][Tkinter 教程10] Text 控件

    已获原作者授权. 原系列地址: Python Tkinter 简介及简例 Text 控件用来显示多行文本. Tkinter 的 Text 控件很强大, 很灵活, 可以实现很多功能. 虽然这个控件的主要 ...

  8. SpringBoot+Swagger2常用注解

    场景 SpringBoot+Swagger2实现可视化API文档流程: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/936166 ...

  9. SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍

    SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍 本篇博文将介绍几种如何处理url中的参数的注解@PathVaribale/@Requ ...

最新文章

  1. LoRDEC: accurate and efficient long read error correction LoRDEC:精确且高效的长read校正
  2. 基于Android设备的Kali Linux渗透测试教程第1章渗透测试
  3. TL-410小路由静态路由问题
  4. 重磅!百度研究院发布2021年十大科技趋势预测
  5. 【Java代码】京东商品全部分类数据获取(建表语句+Jar包依赖+树结构封装+爬虫源代码)包含csv和sql格式数据下载可用
  6. java教程菜鸟教程组合模式,组合实体模式
  7. python 与别的程序通信_《Python》进程之间的通信(IPC)、进程之间的数据共享、进程池...
  8. vb连接mysql未发现_vb连接MySQL遇到的问题解决方法
  9. hashmap转红黑树的阈值为8_面试必考的 HashMap,这篇总结到位了
  10. 阿里巴巴2020首发136道Java高级岗面试题(含答案)
  11. 极客大学架构师训练营 编程的本质与未来 第三课 听课总结
  12. Datawhale 202210 Excel | 第五、六、七章 Excel函数示例 Excel函数列表
  13. 时序数据库在船舶风险管理领域的应用
  14. 最简单的深度学习入门书《动手学深度学习》
  15. MySQL binlog时间异常分析
  16. 第八课: FTP Server设置与加载
  17. Zookeeper + Centos7 详细安装教程
  18. 送给孩子的10句人生箴言
  19. 面对工业4.0,我国工业企业的挑战与对策
  20. 【CV系列】照度和最低照度相关概念

热门文章

  1. SFFAI分享 | 李永露:PaStaNet:Toward Human Activity Knowledge Engine
  2. 水利行业相关规范的资料查阅网站
  3. 「 C++ 参数 」“(WPARAM wParam, LPARAM lParam)信息” 讲解
  4. 欢迎加入QQ群(63503492)讨论技术
  5. Jetson OrinNxNano平台 FPDlink Ⅲ相机采集---双目场景应用
  6. 算法设计与分析之动态规划法
  7. Redis 事务机制实现过程及原理,以及使用事务机制防止库存超卖
  8. (八)InnoDB数据存储结构
  9. 原来OPPO手机的语音翻译这么好用!以前都不知道,真的是浪费了
  10. 20FIC神秘取证,题涉及pc、misc、逆向、服务器、docker范围很广,题目难度较大