知識庫 / JSON RSS 訂閱

Gson 中 @Expose 和 @SerializedName 的區別

JSON
HongKong
10
09:46 PM · Dec 05 ,2025

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

同樣,accountNumberBankAccount 對象中也不應序列化,因為它也是敏感信息。因此,我們必須同時為 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:"));
    }
}

正如預期的那樣,我們沒有看到輸出中的敏感屬性,例如 passwordaccountNumber

{
  "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註解,正如預期,輸出打印了 passwordaccountNumber

{
  "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>。我們可以肯定地説,兩者具有完全不同的功能,正如本文所示。

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

發佈 評論

Some HTML is okay.