使用 Jackson 序列化不可變對象

Jackson
Remote
0
10:28 PM · Nov 30 ,2025

1. 概述

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

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

讓我們更仔細地研究我們剛剛添加的註釋。

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

可以使用作為此註釋參數的兩個模式:PROPERTIESDELEGATING

PROPERTIES 在我們聲明全參數構造函數時最合適,而 DELEGATING 對於單參數構造函數可能很有用。

之後,我們需要使用 @JsonProperty 註釋構造函數參數, 將相應屬性的名稱作為註解值。 在此步驟中,我們必須非常小心,因為所有 屬性名稱必須與我們在序列化過程中使用的名稱匹配。

讓我們看看覆蓋 Employee 對象解序列化的簡單單元測試:

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

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

4. 私有構造函數和構建器

有時,對象會包含一組可選字段。 讓我們考慮另一個類結構,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,代表我們為負責設置屬性的構建器方法添加的前綴。 此參數的默認值為“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.