Gson 中的 @Expose 與 @SerializedName 註釋
1. 簡介
Gson 是 Google 開發的一個開源 Java 程式庫,用於方便將物件轉換為 JSON 以及反之亦然。它提供了高效的序列化和反序列化技術並支援複雜的物件。
Gson 等函式庫提供將 JSON 直接對應到 POJO 的支援。但是,有時必須將特定屬性排除在序列化和反序列化之外。
在本教程中,我們將討論 Gson 函式庫使用的兩個常見且重要的註解@Expose
和@SerializedName
。雖然這兩個註釋都與屬性的可序列化和可反序列化有關,但它們都有各自的用例。
2. Gson 的設置
要開始使用 Gson,我們在pom.xml
中加入它的 Maven依賴項:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
3. Gson 中的@Expose
除非另有說明,否則 Gson 的預設行為是序列化和反序列化 POJO 類別中的所有欄位。 @Expose
註解可以覆寫此行為並控制在序列化和反序列化中包含或排除特定欄位。
如果serialize
和deserialize
屬性設為true
,Gson 僅在 JSON 中包含以Expose
註解的欄位。 serialize
或deserialize
的預設值為true
。
讓我們來看一個例子。我們將使用具有id
、 name
、 age,
和email
等屬性的User
類別。電子郵件是敏感訊息,因此我們將其排除在輸出 JSON 序列化之外:
public class User {
@Expose
String name;
@Expose
int age;
@Expose(serialize = true, deserialize = false)
long id;
@Expose(serialize = false, deserialize = false)
private String email;
// Constructors, Getters, and Setters
}
在上面的程式碼片段中,我們用@Expose
註解name
和age
欄位。缺少明確的serialize
和deserialize
屬性表示它們預設為true
。
我們還應該注意到, email
屬性的兩個註釋都設定為 false。因此,序列化的 JSON 會忽略email
欄位。但是,為了實現這一點,我們應該在建立GsonBuilder
實例時使用excludeFieldsWithoutExposeAnnotation()
。
另一方面,對於id,
序列化過程包含它,而反序列化會忽略 JSON 中存在的任何id
:
@Test
public void givenUserObject_whenSerialized_thenCorrectJsonProduced() {
User user = new User("John Doe", 30, "[email protected]");
user.setId(12345L);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(user);
// Verify that name, age, and id are serialized, but email is not
assertEquals("{\"name\":\"John Doe\",\"age\":30,\"id\":12345}", json);
}
@Test
public void givenJsonInput_whenDeserialized_thenCorrectUserObjectProduced() {
String jsonInput = "{\"name\":\"Jane Doe\",\"age\":25,\"id\":67890,\"email\":\"[email protected]\"}";
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.create();
User user = gson.fromJson(jsonInput, User.class);
// Verify that name and age are deserialized, but email and id are not
assertEquals("Jane Doe", user.name);
assertEquals(25, user.getAge());
assertEquals(0, user.getId()); // id is not deserialized
assertNull(user.getEmail()); // email is not deserialized
}
我們在第一個測試中看到序列化的 JSON 不包含email
屬性。在第二個單元測試中,我們斷言反序列化的User
物件忽略了其 JSON 中的email
欄位。
4. Gson 中的SerializedName
我們來了解Gson中SerializedName
註解的使用。當我們建立 Java 類別並定義其屬性時,JSON 表示可能需要與類別中定義的名稱不同的名稱。此註釋將 POJO 屬性對應到其序列化 JSON 表示中的特定名稱。
按照我們之前的例子,這次我們希望User
的 JSON 表示形式以firstName
作為欄位名稱而不是name
:
public class User {
@Expose
@SerializedName("firstName")
String name;
}
我們的單元測試現在應該斷言firstName
欄位:
@Test
public void givenUserObject_whenSerialized_thenCorrectJsonProduced() {
User user = new User("John Doe", 30, "[email protected]");
user.setId(12345L);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(user);
assertEquals("{\"firstName\":\"John Doe\",\"age\":30,\"id\":12345}", json);
}
SerailizedName
支援一個名為alternate
的附加屬性,該屬性接受屬性的備用名稱列表,並告訴解析器在反序列化時尋找任一值。當屬性名稱可能根據外部或遺留系統而變化時,這是一個強大的功能。
讓我們考慮一個使用fullName
而不是firstName.
我們可以透過正確填寫alternate
屬性來正確解碼這些:
public class User {
@Expose
@SerializedName(value = "firstName", alternate = { "fullName", "name" })
String name;
}
@Test
public void givenJsonWithAlternateNames_whenDeserialized_thenCorrectNameFieldMapped() {
String jsonInput1 = "{\"firstName\":\"Jane Doe\",\"age\":25,\"id\":67890,\"email\":\"[email protected]\"}";
String jsonInput2 = "{\"fullName\":\"John Doe\",\"age\":30,\"id\":12345,\"email\":\"[email protected]\"}";
String jsonInput3 = "{\"name\":\"Alice\",\"age\":28,\"id\":54321,\"email\":\"[email protected]\"}";
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
User user1 = gson.fromJson(jsonInput1, User.class);
User user2 = gson.fromJson(jsonInput2, User.class);
User user3 = gson.fromJson(jsonInput3, User.class);
// Verify that the name field is correctly deserialized from different JSON field names
assertEquals("Jane Doe", user1.getName());
assertEquals("John Doe", user2.getName());
assertEquals("Alice", user3.getName());
}
我們可以從輸入的 JSON 有效負載中正確反序列化名稱屬性,並將fullName
和firstName
作為屬性名稱。
5. @SerializedName
和@Expose
之間的區別
讓我們快速總結一下這兩個註釋之間的主要區別:
@SerializedName |
@Expose |
---|---|
將 Java POJO 欄位對應到 JSON 欄位名稱 | 標記欄位是否應該序列化或反序列化 |
value 屬性是必需的,並且可以使用可選的alternate 屬性 |
有兩個可選屬性: serialize 和deserialize |
開箱即用,無需任何配置 | 僅在使用GsonBuilder 配置時有效,且需要GsonBuilder.excludeFieldsWithoutExposeAnnotation() |
6. 結論
在本文中,我們了解了SerializedName
和@Expose Expose
工作原理以及如何使用它們在 Java 中處理 JSON 序列化和反序列化。我們也強調了兩者之間的主要區別。
與往常一樣,程式碼可在 GitHub 上取得。