Jackson 是一个流行的库,用于将 Java 对象序列化/反序列化为各种文本格式。ObjectMapper类是该库处理 JSON 格式的主要方式。对于其他格式,我们有它的后代(XmlMapper、YAMLMapper)。由于继承,我们可以通过单一界面以一致的方式处理所有格式。
下载 jar 文件
在学习示例之前,我们需要下载 Jackson jar 文件并将其连接到 IntelliJ IDEA 中的项目。下面以jackson-databind为例,看看如何搜索需要的文件:
-
转到Maven 存储库网站。
-
在搜索框中输入“ jackson-databind ”。您将获得以下内容:
-
第一个搜索结果是我们感兴趣的。点击链接。
-
有时可能需要特定版本的库来确保与项目中其他组件的兼容性。最新版本应该可以工作(在编写本课程时,它是 2.13.2.2)。点击链接。
-
在打开的页面上,您需要“捆绑包”链接:
-
使用此链接下载 jar 文件。
按照类似的过程,您可以找到并下载其余必要的 jar 文件:
下载所有必要的文件后,将它们连接到 IntelliJ IDEA 中的项目:
-
打开项目设置(您可以使用Ctrl+Alt+Shift+S组合键)。
-
去图书馆。
-
按+,然后按“Java”。选择所有下载的文件。这是我们最终应该得到的:
-
我们的准备工作到此结束。现在我们可以试用ObjectMapper了。
序列化为 JSON
首先,让我们将一些对象序列化为 JSON:
import com.fasterxml.jackson.databind.ObjectMapper;
class Book {
public String title;
public String author;
public int pages;
}
public class Solution {
public static void main(String[] args) throws Exception {
Book book = new Book();
book.title = "Good Omens";
book.author = "Pratchett T., Gaiman N.";
book.pages = 383;
ObjectMapper mapper = new ObjectMapper();
String jsonBook = mapper.writeValueAsString(book);
System.out.println(jsonBook);
}
}
运行main会给你这个输出:
ObjectMapper有很多高级设置。让我们使用其中之一来使 JSON 字符串更具可读性。创建后对象映射器对象,执行这条语句:
输出中的信息保持不变,但现在有缩进和换行符:
“标题”:“好兆头”,
“作者”:“普拉切特 T.,盖曼 N.”,
“页数”:383
}
从 JSON 反序列化
现在让我们做相反的动作:我们将一个字符串反序列化为一个对象。为了能够看到程序在做什么,让我们重写Book类中的toString方法:
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
", pages=" + pages +
'}';
}
我们将在main方法中执行以下操作:
public static void main(String[] args) throws Exception {
String jsonString = "{\"title\":\"Good Omens\",\"author\":\"Pratchett T., Gaiman N.\",\"pages\":383}";
Book book = new ObjectMapper().readValue(jsonString, Book.class);
System.out.println(book);
}
输出:
readValue方法被重载了——它有很多变体,可以接受一个文件、一个链接、各种输入流等。为简单起见,我们的示例使用了一个接受 JSON 字符串的变体。
如上所述,ObjectMapper有很多设置。让我们来看看其中的几个。
忽略未知属性
考虑这样一种情况,JSON 字符串具有Book类中不存在的属性:
public static void main(String[] args) throws Exception {
String jsonString = """
{
"title" : "Good Omens",
"author" : "Pratchett T., Gaiman N.",
"pages" : 383,
"unknown property" : 42
}""";
ObjectMapper mapper = new ObjectMapper();
Book book = mapper.readValue(jsonString, Book.class);
System.out.println(book);
}
执行这段代码给我们一个UnrecognizedPropertyException。这是默认行为,但我们可以更改它:
ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
创建时对象映射器对象,我们使用configure方法将相应的设置设置为false。configure方法修改调用它的对象,然后返回同一个对象,所以我们可以用不同的方式进行调用:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
就功能而言,此表示法与前一个表示法一样。
如果我们现在运行main方法,反序列化将成功,未知属性将被忽略。
方便的注释
Jackson 为我们提供了几个注释,允许我们以各种方式自定义序列化过程。让我们来看看一些最有用的:
@JsonIgnore — 此注释位于序列化/反序列化期间应忽略的元素上方:
class Book {
public String title;
@JsonIgnore
public String author;
public int pages;
}
这里的作者在序列化期间,字段不会包含在生成的 JSON 中。反序列化后,作者字段将获得默认值 (null),即使 JSON 具有不同的值。
@JsonFormat — 此注释允许您设置序列化数据的格式。让我们在Book类中再添加一个字段Date:
class Book {
public String title;
public String author;
public int pages;
public Date createdDate = new Date();
}
序列化后,我们得到以下 JSON:
“标题”:“好兆头”,
“作者”:“Pratchett T.,Gaiman N.”,
“页面”:383,
“createdDate”:1649330880788
}
如您所见,日期被序列化为数字。我们将添加注释并设置格式:
class Book {
public String title;
public String author;
public int pages;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public Date createdDate = new Date();
}
现在序列化的结果是:
“标题”:“好兆头”,
“作者”:“Pratchett T.,Gaiman N.”,
“页面”:383,
“createdDate”:“2022-04-07”
}
@JsonProperty — 此注释允许您更改表示序列化字段的属性的名称。您还可以使用此注释标记方法。如果这样做,那么它们的返回值将在序列化期间转换为 JSON 属性:
class Book {
@JsonProperty("name")
public String title;
public String author;
public int pages;
@JsonProperty("quotedTitle")
public String getQuotedTitle() {
return "\"" + title + "\"";
}
}
序列化结果:
"author" : "Pratchett T., Gaiman N.",
"pages" : 383,
"name" : "Good Omens",
"quotedTitle" : "\"Good Omens\""
}
@JsonInclude — 使用此注释,您可以指定序列化字段必须满足的条件。您可以将其应用于单个领域或整个班级。首先,让我们尝试序列化一个带有未初始化字段的对象:
public class Solution {
public static void main(String[] args) throws Exception {
Book book = new Book();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String jsonBook = mapper.writeValueAsString(book);
System.out.println(jsonBook);
}
}
序列化结果:
“标题”:空,
“作者”:空,
“页面”:0
}
如果您添加注释:
@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
public String title;
public String author;
public int pages;
}
然后我们得到这个结果:
“页面”:0
}
现在不序列化为null的字段。
@JsonPropertyOrder — 此注释允许您设置字段序列化的顺序:
@JsonPropertyOrder({"author", "title", "pages"})
class Book {
public String title;
public String author;
public int pages;
}
序列化结果:
"author" : "Pratchett T., Gaiman N.",
"title" : "Good Omens",
"pages" : 383
}
现在,只需记住如何使用注释。在本模块结束时,我们将更好地了解它们,甚至创建我们自己的注释。
XML 中的序列化和反序列化
如果我们需要序列化为 XML,我们可以使用所有相同的设置和注释。唯一的区别是映射器对象:
public static void main(String[] args) throws Exception {
Book book = new Book();
book.title = "Good Omens";
book.author = "Pratchett T., Gaiman N.";
book.pages = 383;
ObjectMapper mapper = new XmlMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String xmlBook = mapper.writeValueAsString(book);
System.out.println(xmlBook);
}
输出:
<title>好兆头</title>
<author>Pratchett T., Gaiman N.</author>
<pages>383</pages>
</Book>
XML反序列化:
public static void main(String[] args) throws Exception {
String xmlString = """
<Book>
<title>Good Omens</title>
<author>Pratchett T., Gaiman N.</author>
<pages>383</pages>
</Book>""";
ObjectMapper mapper = new XmlMapper();
Book book = mapper.readValue(xmlString, Book.class);
System.out.println(book);
}
YAML 中的序列化和反序列化
我们像处理 XML 一样处理 YAML:
public static void main(String[] args) throws Exception {
Book book = new Book();
book.title = "Good Omens";
book.author = "Pratchett T., Gaiman N.";
book.pages = 383;
ObjectMapper mapper = new YAMLMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String yamlBook = mapper.writeValueAsString(book);
System.out.println(yamlBook);
}
输出:
标题:“好兆头”
作者:“Pratchett T., Gaiman N.”
页数:383
YAML 的反序列化:
public static void main(String[] args) throws Exception {
String yamlString = """
---
title: "Good Omens"
author: "Pratchett T., Gaiman N."
pages: 383""";
ObjectMapper mapper = new YAMLMapper();
Book book = mapper.readValue(yamlString, Book.class);
System.out.println(book);
}
GO TO FULL VERSION