知識庫 / JSON / Jackson RSS 訂閱

使用 Jackson 序列化不可變對象

Jackson
HongKong
6
09:54 PM · Dec 05 ,2025

1. 概述

在本快速教程中,我們將展示兩種不同的方法來反序列化不可變 Java 對象,使用 Jackson JSON 處理庫。

2. 為什麼使用不可變對象?

一個不可變對象是指在創建之初,其狀態就保持不變的對象。這意味着無論用户調用該對象的方法,對象始終保持相同的行為

不可變對象在設計一個需要多線程環境的系統時非常有用,因為不可變性通常保證了線程安全。

另一方面,不可變對象在我們需要處理外部來源的數據時也很有用。例如,可以是用户輸入或存儲中的數據。在這種情況下,保持接收到的數據不變並保護它免受意外或未預期的更改至關重要

讓我們看看如何反序列化一個不可變對象。

3. 公共構造函數

請考慮 Employee 類結構。它有兩個必需字段:idname,因此我們定義了一個 公共的、全參數構造函數,它具有與對象字段相匹配的一組參數:

public class Employee {

    private final long id;
    private final String name;

    public Employee(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters
}

這樣一來,我們就能在創建對象時初始化所有對象的字段。 字段聲明中的最終修飾符不會允許我們在未來更改其值。 為了使該對象可進行反序列化,我們只需要向構造函數添加幾個註解:

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public Employee(@JsonProperty("id") long id, @JsonProperty("name") String name) {
    this.id = id;
    this.name = name;
}

讓我們更詳細地瞭解我們剛剛添加的註釋。

首先,<em @JsonCreator</em> 告訴 Jackson 解序列器使用指定構造函數進行解序列化。

可以使用註解的兩個模式作為參數:<em PROPERTIES</em><em DELEGATING</em>

<em PROPERTIES</em> 最適合我們聲明全參數構造函數,而 <em DELEGATING</em> 則可能對單參數構造函數有幫助。

接下來,我們需要使用 <em @JsonProperty</em> 註解來標記每個構造函數參數,該註解的值表示相應屬性的名稱。 在此步驟中,務必小心,因為所有 <strong>屬性名稱</strong> 必須與我們在序列化過程中使用的名稱相匹配。

以下是一個涵蓋 <em Employee</em> 對象解序列化的簡單單元測試:

String json = "{\"name\":\"Frank\",\"id\":5000}";
Employee employee = new ObjectMapper().readValue(json, Employee.class);

assertEquals("Frank", employee.getName());
assertEquals(5000, employee.getId());

4. 私有構造函數和 Builder

有時,對象可能包含一組可選字段。 讓我們考慮另一個類結構,Person,它包含一個可選的 age 字段:

public class Person {
    private final String name;
    private final Integer age;

    // getters
}

當我們有大量的此類字段時,創建公共構造函數可能會變得繁瑣。換句話説,我們需要聲明大量的參數併為每個參數添加 @JsonProperty 註解。 這樣會導致大量的重複聲明,使我們的代碼臃腫且難以閲讀。

這種情況通常會藉助經典的 Builder 模式。 讓我們看看如何在反序列化中利用它的力量。 首先,讓我們聲明 一個包含所有參數的私有構造函數和一個 Builder

private Person(String name, Integer age) {
    this.name = name;
    this.age = age;
}

static class Builder {
    String name;
    Integer age;
    
    Builder withName(String name) {
        this.name = name;
        return this;
    }
    
    Builder withAge(Integer age) {
        this.age = age;
        return this;
    }
    
    public Person build() {
        return new Person(name, age);
    } 
}

為了讓 Jackson 解序列化器使用這個 Builder,我們只需要在代碼中添加兩個註解。首先,我們需要用 @JsonDeserialize 註解標記我們的類,並傳遞一個 builder 參數,該參數包含 構建器的完全限定域名

之後,我們需要用 @JsonPOJOBuilder 註解標記構建器類本身:

@JsonDeserialize(builder = Person.Builder.class)
public class Person {
    //...
    
    @JsonPOJOBuilder
    static class Builder {
        //...
    }
}

請注意,我們可以自定義構建過程中使用的方法的名稱。

參數 buildMethodName 默認為“build”,代表我們在構建器準備生成新對象時調用的 方法名稱

另一個參數 withPrefix 代表 我們在設置屬性時添加的 prefix。 此參數的默認值為“with”,因此我們在示例中未指定這些參數。

讓我們來看一個涵蓋 Person 對象反序列化的簡單單元測試:

String json = "{\"name\":\"Frank\",\"age\":50}";
Person person = new ObjectMapper().readValue(json, Person.class);

assertEquals("Frank", person.getName());
assertEquals(50, person.getAge().intValue());

5. 結論

在本文中,我們瞭解到如何使用 Jackson 庫反序列化不可變對象。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.