Gson 通过@JsonAdapter 自定义(反)序列化
在这篇文章中,我们将展示如何简化(反)序列化的自定义。 在过去的几篇文章中,我们演示了如何自定义序列化.html)、反序列化tml)以及如何利用实例创建器。
所有这些选项都只能通过自定义 Gson 实例和一些样板代码获得。 Gson 2.7 引入了一个简单的注解,我们可以节省大量代码并获得相同的结果。 如果大家对 @JsonAdapter
感兴趣,请继续阅读!
@JsonAdapter 注解
我们将在本教程中使用的
@JsonAdapter
注解仅受 Gson 2.7(或更高版本)支持!
如果大家阅读过我们之前关于自定义(反)序列化的博客文章,就会知道一般结构并不太复杂,但总是有几行样例代码:
GsonBuilder gsonBuilder = new GsonBuilder();
Type merchantListType = new TypeToken<List<Merchant>>() {}.getType();
JsonSerializer<List<Merchant>> serializer = ...;
gsonBuilder.registerTypeAdapter(merchantListType, serializer);
Gson customGson = gsonBuilder.create();
String customJSON = customGson.toJson(subscription);
上面的代码片段向我们展示了一个自定义序列化程序的示例。 我们仍然需要 JsonSerializer
接口的实现,但是可以简化它周围的其他代码。
自定义序列化
第一步是拉出上面代码片段中的 serializer
对象并将其移动到一个类中。 该类具有与匿名声明相同的设置,因为我们将其作为对象完成
public class MerchantListSerializer implements JsonSerializer<List<Merchant>> {
@Override
public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
JsonArray jsonMerchant = new JsonArray();
for (Merchant merchant : src) {
jsonMerchant.add("" + merchant.getId());
}
return jsonMerchant;
}
}
一旦我们将它包装在一个公共类中,就可以在 @JsonAdapter
注解中使用它。 @JsonAdapter
注解 ,就像我们在之前的文章中探讨的其他注解一样,被添加到 Java 模型中。 在上面的示例中,我们需要更改包含 List<Merchant>
属性的模型。
例如:
public class UserSubscriptionAnnotation {
String name;
String email;
int age;
boolean isDeveloper;
// new!
@JsonAdapter(MerchantListSerializer.class)
List<Merchant> merchantList;
}
需要自定义序列化程序的属性将由 @JsonAdapter
注解增强。 注解只接受一个参数:类引用。 该类需要实现 JsonSerializer
或 JsonDeserializer
。
以下所有 Gson 转换都将使用我们的自定义(反)序列化。 我们将不再需要自定义 Gson 实例。 因此,以下代码段就足够了:
UserSubscriptionAnnotation subscription = new UserSubscriptionAnnotation(
"zadmei",
"zadmei_onmpw@163.com",
26,
true,
subscribedMerchants);
Gson gson = new Gson();
String fullJSON = gson.toJson(subscription);
我们可以完全摆脱 GsonBuilder
部分,只需使用默认的 new Gson()
实例
自定义反序列化
相同的方法和注释也适用于自定义反序列化。 如果大家查看我们自定义反序列化文章中的代码,就会发现以下设置代码:
GsonBuilder gsonBuilder = new GsonBuilder();
JsonDeserializer<UserDate> deserializer = ...;
gsonBuilder.registerTypeAdapter(UserDate.class, deserializer);
Gson customGson = gsonBuilder.create();
UserDate customObject = customGson.fromJson(userJson, UserDate.class);
再一次,替代解决方案是将其从具有注册类型适配器的自定义 Gson 实例更改为注解模型。
首先,我们必须将反序列化器提取到一个类中:
public class UserDateDeserializer implements JsonDeserializer<UserDate> {
@Override
public UserDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
Date date = new Date(
jsonObject.get("year").getAsInt(),
jsonObject.get("month").getAsInt(),
jsonObject.get("day").getAsInt()
);
return new UserDate(
jsonObject.get("name").getAsString(),
jsonObject.get("email").getAsString(),
jsonObject.get("isDeveloper").getAsBoolean(),
jsonObject.get("age").getAsInt(),
date
);
}
}
如大家所见,deserialize()
中的代码保持不变。
第二步,给模型添加注解:
@JsonAdapter(UserDateDeserializer.class)
public class UserDate {
private String _name;
private String email;
private boolean isDeveloper;
private int age;
private Date registerDate
}
与前面通过注解进行自定义序列化的示例略有不同的是,我们注解的是整个类,而不是特定的属性。 两种方法都是可能的和有用的!
反序列化现在简化为一行代码:
UserDate standardObject = new Gson().fromJson(userJson, UserDate.class);
超出@JsonAdapter 的范围:多种自定义
Java 注解的一个限制是我们只能为每个类(或属性)添加一个注解。 如果我们的模型或属性之一需要自定义序列化程序和自定义反序列化程序,则我们需要通过带有 registerTypeAdapter()
调用的自定义 Gson 实例继续使用很长时间。
总结
在本篇文章中,我们了解了如何使用 @JsonAdapter
注解来节省大量样例代码并简化代码库。 虽然它没有添加任何新功能,但它使我们的代码更清晰、更易于理解。
此外,它通过只为每个模型(和属性)允许一个注解来防止我们意外注册多个自定义(反)序列化器。