1. 概述
本教程將介紹 Gson 庫中的 <em @Expose</em> 和 <em @SerializedName</em> 註解。<em @Expose</em> 幫助控制哪些類屬性可以進行序列化或反序列化,而 <em @SerializedName</em> 則在序列化和反序列化過程中,幫助將對象的屬性名稱映射到 JSON 字符串中的屬性鍵名,以及反之亦然。
2. <em @Expose>
在某些情況下,類中屬性的某些敏感值不應被序列化或轉換為 JSON 字符串。為了處理這種情況,Gson 提供了 > 標註,該標註具有兩個 屬性: 和 。
假設 屬性在 類中不應被序列化,因為它包含敏感信息。因此,必須使用 標註裝飾 屬性:
public class Person {
@Expose(serialize = true)
private String firstName;
@Expose(serialize = true)
private String lastName;
@Expose()
private String emailAddress;
@Expose(serialize = false)
private String password;
@Expose(serialize = true)
private List<BankAccount> bankAccounts;
//General getters and setters..
}
同樣,accountNumber 在 BankAccount 對象中也不應序列化,因為它也是敏感信息。因此,我們必須同時為 accountNumber 屬性添加註解 @Expose(serialize=false):
public class BankAccount {
@Expose(serialize = false, deserialize = false)
private String accountNumber;
@Expose(serialize = true, deserialize = true)
private String bankName;
//general getters and setters..
}
現在,要將對象轉換為 JSON 字符串,我們不能使用默認的 Gson 對象,該對象是通過使用 new 運算符創建的。我們必須使用 GsonBuilder 類,通過使用 excludeFieldsWithoutExposeAnnotation() 設置實例化 Gson 類。
讓我們看一下 PersonSerializer 類:
public class PersonSerializer {
private static final Gson configuredGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
private static final Gson defaultGson = new Gson();
public static String serializeWithConfiguredGson(Person person) {
return configuredGson.toJson(person);
}
public static String serializeWithDefaultGson(Person person) {
return defaultGson.toJson(person);
}
}讓我們測試一下 serializeWithConfiguredGson() 方法:
public class PersonSerializerUnitTest {
@Test
public void whenUseCustomGson_thenDonotSerializeAccountNumAndPassword () {
String personJson = PersonSerializer.serializeWithConfiguredGson(person);
assertFalse("Test failed: password found", personJson.contains("password"));
assertFalse("Test failed: account number found", personJson.contains("accountNumber:"));
}
}正如預期的那樣,我們沒有看到輸出中的敏感屬性,例如 password 和 accountNumber。
{
"firstName":"Parthiv",
"lastName":"Pradhan","email":"[email protected]",
"bankAccounts":[{"bankName":"Bank of America"},{"bankName":"Bank of America"}]
}同樣,我們來測試一下 serializeWithDefaultGson() 方法:
@Test
public void whenUseDefaultGson_thenSerializeAccountNumAndPassword () {
String personJson = PersonSerializer.serializeWithDefaultGson(person);
assertTrue("Test failed: password not found", personJson.contains("password"));
assertTrue("Test failed: account number not found", personJson.contains("accountNumber"));
}正如之前討論的,默認的 Gson對象無法識別 @Expose註解,正如預期,輸出打印了 password 和 accountNumber:
{
"firstName":"James","lastName":"Cameron","email":"[email protected]",
"password":"secret",
"bankAccounts":
[
{"accountNumber":"4565432312","bankName":"Bank of America"},
{"accountNumber":"4565432616","bankName":"Bank of America"}
]
}為了在序列化時排除屬性,以便進行更高級的用例,我們可以使用 ExclusionStrategy。
3. <em @SerializedName
@SerializedName 註解就像一個自定義轉換器。通常,我們首先將對象轉換為 JSON 字符串,然後再修改其屬性鍵,然後將其作為參數發送到 Web 服務。
同樣,在將 JSON 字符串轉換為對象時,我們必須將其屬性鍵映射到對象的屬性名稱。Gson 庫巧妙地將這兩個步驟結合起來,藉助一個單一的註解,@SerializedName。 真是簡單方便!
在序列化時,我們經常希望生成儘可能小的 payload。讓我們嘗試序列化下面的 Country c 類,使用比屬性名稱更短的自定義鍵名稱:
public class Country {
@SerializedName(value = "name")
private String countryName;
@SerializedName(value = "capital")
private String countryCapital;
@SerializedName(value = "continent")
private String continentName;
//general getters and setters..
}現在,讓我們將 Country 對象轉換為 JSON 格式:
public class PersonSerializer {
private static final Gson defaultGson = new Gson();
public static String toJsonString(Object obj) {
return defaultGson.toJson(obj);
}
}現在是時候檢查一下該方法是否有效:
@Test
public void whenUseSerializedAnnotation_thenUseSerializedNameinJsonString() {
String countryJson = PersonSerializer.toJsonString(country);
logger.info(countryJson);
assertFalse("Test failed: No change in the keys", countryJson.contains("countryName"));
assertFalse("Test failed: No change in the keys", countryJson.contains("contentName"));
assertFalse("Test failed: No change in the keys", countryJson.contains("countryCapital"));
assertTrue("Test failed: No change in the keys", countryJson.contains("name"));
assertTrue("Test failed: No change in the keys", countryJson.contains("continent"));
assertTrue("Test failed: No change in the keys", countryJson.contains("capital"));
}正如預期的那樣,我們發現屬性鍵與我們提供的 @SerializedName 註解所對應的內容完全一致:
{"name":"India","capital":"New Delhi","continent":"Asia"}讓我們看看相同的標註是否能將上述 JSON 轉換為 國家 對象。為此,我們將使用 fromJsonString() 方法:
public class PersonSerializer {
private static final Gson defaultGson = new Gson();
public static Country fromJsonString(String json) {
return defaultGson.fromJson(json, Country.class);
}
}讓我們檢查一下該方法是否有效:
@Test
public void whenJsonStrCreatedWithCustomKeys_thenCreateObjUsingGson() {
String countryJson = PersonSerializer.toJsonString(country);
Country country = PersonSerializer.fromJsonString(countryJson);
assertEquals("Fail: Object creation failed", country.getCountryName(), "India");
assertEquals("Fail: Object creation failed", country.getCountryCapital(), "New Delhi");
assertEquals("Fail: Object creation failed", country.getContinentName(), "Asia");
}該方法可以創建 Country 對象:
Country{countryName='India', countryCapital='New Delhi', continentName='Asia'}4. 結論
在本文中,我們學習了 Gson 兩個重要的註解:<em @Expose</em> 和 <em @SerializedName</em>。我們可以肯定地説,兩者具有完全不同的功能,正如本文所示。