Jackson 是一個流行的庫,用於將 Java 對象序列化/反序列化為各種文本格式。ObjectMapper類是該庫處理 JSON 格式的主要方式對於其他格式,我們有它的後代(XmlMapperYAMLMapper)。由於繼承,我們可以通過單一界面以一致的方式處理所有格式。

下載 jar 文件

在學習示例之前,我們需要下載 Jackson jar 文件並將其連接到 IntelliJ IDEA 中的項目。下面以jackson-databind為例,看看如何搜索需要的文件:

  1. 轉到Maven 存儲庫網站。

  2. 在搜索框中輸入“ jackson-databind ”。您將獲得以下內容:

  3. 第一個搜索結果是我們感興趣的。點擊鏈接。

  4. 有時可能需要特定版本的庫來確保與項目中其他組件的兼容性。最新版本應該可以工作(在撰寫本課程時,它是 2.13.2.2)。點擊鏈接。

  5. 在打開的頁面上,您需要“捆綁包”鏈接:

  6. 使用此鏈接下載 jar 文件。

按照類似的過程,您可以找到並下載其餘必要的 jar 文件:

下載所有必需的文件後,將它們連接到 IntelliJ IDEA 中的項目:

  1. 打開項目設置(您可以使用Ctrl+Alt+Shift+S組合鍵)。

  2. 圖書館

  3. +,然後按“Java”。選擇所有下載的文件。這是我們最終應該得到的:

  4. 我們的準備工作到此結束。現在我們可以試用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會給你這個輸出:

{"title":"Good Omens","author":"Pratchett T., Gaiman N.","pages":383}

ObjectMapper很多高級設置。讓我們使用其中之一來使 JSON 字符串更具可讀性。創建後對象映射器對象,執行這條語句:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

輸出中的信息保持不變,但現在有縮進和換行符:

{
  “標題”:“好兆頭”,
  “作者”:“普拉切特 T.,蓋曼 N.”,
 “頁數”:383
}

從 JSON 反序列化

現在讓我們做相反的動作:我們將一個字符串反序列化為一個對象。為了能夠看到程序在做什麼,讓我們重寫Book類中的toString方法:


@Override
public String toString() {
	return "Book{" +
        	"title='" + title + '\'' +
        	", author='" + author + '\'' +
        	", pages=" + pages +
        	'}';
}

我們將在主要方法中執行以下操作:


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);
}

輸出:

Book{title='Good Omens', author='Pratchett T., Gaiman N.', pages=383}

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);
}

輸出:

 <Book>
  <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);
}