1. 概述
在本快速教程中,我們將展示兩種不同的方法來反序列化不可變 Java 對象,使用 Jackson JSON 處理庫。
2. 為什麼使用不可變對象?
一個不可變對象是指在創建之初,其狀態就保持不變的對象。這意味着無論用户調用該對象的方法,對象始終保持相同的行為。
不可變對象在設計一個需要多線程環境的系統時非常有用,因為不可變性通常保證了線程安全。
另一方面,不可變對象在我們需要處理外部來源的數據時也很有用。例如,可以是用户輸入或存儲中的數據。在這種情況下,保持接收到的數據不變並保護它免受意外或未預期的更改至關重要。
讓我們看看如何反序列化一個不可變對象。
3. 公共構造函數
請考慮 Employee 類結構。它有兩個必需字段:id 和 name,因此我們定義了一個 公共的、全參數構造函數,它具有與對象字段相匹配的一組參數:
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 庫反序列化不可變對象。