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、@Expose 注解
Gson 默认会序列化和反序列化 POJO 类的所有字段,除非另有指定。@Expose
注解可覆盖此行为,控制特定字段是否参与序列化或反序列化。
若字段的 serialize
和 deserialize
属性设为 true
,Gson 仅会处理带有 @Expose
注解的字段。这两个属性的默认值均为 true
。
以下示例展示了一个包含 id
、name
、age
和 email
的 User
类。由于 email
是敏感信息,我们将其从输出的 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;
// 构造函数、Getter、Setter 省略
}
在上述代码片段中,我们用 @Expose
标注了 name
和 age
字段。未显式设置 serialize
和 deserialize
属性意味着它们默认为 true
。
需注意 email
属性的两个注解值均设为 false
,因此序列化的 JSON 会忽略该字段。但需在创建 GsonBuilder
实例时调用 excludeFieldsWithoutExposeAnnotation()
方法才能使此配置生效。
另一方面,对于 id
字段,序列化过程会包含它,而反序列化时会忽略 JSON 中存在的任何 id
值:
@Test
public void givenUserObject_whenSerialized_thenCorrectJsonProduced() {
User user = new User("John Doe", 30, "john.doe@example.com");
user.setId(12345L);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(user);
// 验证 `name`、`age` 和 `id` 被序列化,而 `email` 未被包含
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\":\"jane.doe@example.com\"}";
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.create();
User user = gson.fromJson(jsonInput, User.class);
// 验证 `name` 和 `age` 被反序列化,而 `email` 和 `id` 未被处理
assertEquals("Jane Doe", user.name);
assertEquals(25, user.getAge());
assertEquals(0, user.getId()); // id 未被反序列化
assertNull(user.getEmail()); // email 未被反序列化
}
第一个测试中可见序列化的 JSON 未包含 email
属性。第二个单元测试验证了反序列化的 User
对象会忽略 JSON 中的 email
字段。
4、@SerializedName 注解
下面我们了解 Gson 中 @SerializedName
注解的用途。当 Java 类的属性名与其 JSON 表示需要不同时,该注解可将 POJO 属性映射到 JSON 中的指定字段名。
继续之前的示例,假设这次我们需要将 User
类的 name
字段在 JSON 中表示为 firstName
:
public class User {
@Expose
@SerializedName("firstName")
String name;
}
测试,验证 firstName
字段:
@Test
public void givenUserObject_whenSerialized_thenCorrectJsonProduced() {
User user = new User("John Doe", 30, "john.doe@example.com");
user.setId(12345L);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(user);
assertEquals("{\"firstName\":\"John Doe\",\"age\":30,\"id\":12345}", json);
}
@SerializedName
支持一个名为 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\":\"jane.doe@example.com\"}";
String jsonInput2 = "{\"fullName\":\"John Doe\",\"age\":30,\"id\":12345,\"email\":\"john.doe@example.com\"}";
String jsonInput3 = "{\"name\":\"Alice\",\"age\":28,\"id\":54321,\"email\":\"alice@example.com\"}";
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);
// 验证 `name` 字段可从不同的 JSON 字段名正确反序列化。
assertEquals("Jane Doe", user1.getName());
assertEquals("John Doe", user2.getName());
assertEquals("Alice", user3.getName());
}
系统能够正确地从输入 JSON 数据中反序列化 name
属性,无论该属性在 JSON 中被命名为 fullName
还是 firstName
。
5、@SerializedName 和 @Expose 的对比
以下是两个注解的核心区别总结:
@SerializedName |
@Expose |
---|---|
将 Java POJO 字段映射到 JSON 字段名 | 标记字段是否应参与序列化或反序列化 |
必须提供 value 属性,可选择使用 alternate 属性 |
提供两个可选属性:serialize 和 deserialize |
开箱即用,无需任何配置 | 需通过 GsonBuilder 配置且必须调用 GsonBuilder.excludeFieldsWithoutExposeAnnotation() 才能生效 |
6、总结
本文介绍了如何使用 Gson 中的 @SerializedName
和 @Expose
注解来处理 Java 中的 JSON 序列化与反序列化,同时强调了两者的核心差异。
Ref:https://www.baeldung.com/gson-expose-vs-serializedname-annotations