Gson 自定义反序列化基础

在这篇文章中,我们将了解如何实现自定义 Gson 反序列化。 如果服务器以与客户端的应用程序数据模型不匹配的格式向我们发送数据,请继续阅读!


自定义反序列化

在现代应用程序中,API 以没有 Java 等效项或不适合我们的应用程序的结构发送数据是很常见的。 在这些情况下,拥有一个自定义反序列化器非常有用,它采用 JSON 消息的数据格式并将其转换为对 Java 端有用的东西。

例如,让我们看一下以下 JSON:

{
    "year": 116,
    "month": 5,
    "day": 21,
    "age": 26,
    "email": "zadmei_onmpw@163.com",
    "isDeveloper": true,
    "name": "zadmei"
}

底部的四个属性是有意义的,并且在 Java 中具有直接等效性。 然而,前三个代表一个简单的日期对象。 当然,我们可以只创建一个 Java 模型,它也有三个 int 值。 但这在我们的应用程序中会非常不方便,因为我们总是必须处理将这三个组合成一个有目的的日期对象。

更好的方法是自定义反序列化并立即将它们组合到日期对象。 在应用程序中,我们永远不会知道服务器以这种格式发送它,并且我们可以抽象出服务器和客户端之间的差异。

在此示例中,我们的目标是使用以下 Java 模型:

public class UserDate {  
    private String name;
    private String email;
    private boolean isDeveloper;
    private int age;
    private Date registerDate;
}

自定义反序列化的方法几乎与自定义序列化相同。 因此,阅读自定义序列化可能会有所帮助。

简而言之,我们需要使用自定义 Gson 实例并调用 registerTypeAdapter() 方法。 registerTypeAdapter() 需要两个参数。 第一个是我们要定制的整体模型的类型。 第二个参数是类型化 JsonDeserializer 的实例。

GsonBuilder gsonBuilder = new GsonBuilder();

JsonDeserializer<UserDate> deserializer = ...; // will implement in a second  
gsonBuilder.registerTypeAdapter(UserDate.class, deserializer);

Gson customGson = gsonBuilder.create();  
UserDate customObject = customGson.fromJson(userJson, UserDate.class);  

关键部分是 JsonDeserializer 的实现。 我们需要实现一个 deserialize() 方法。 它向我们传递一个 JsonElement,其中包含实际输入 JSON 和必须返回的预期类型。

根据输入的 JSON,我们必须创建 Java 模型。 在大多数情况下,Gson 可以自动为我们完成所有这些工作。 当我们需要自定义反序列化时,可能需要手动执行一些操作。

继续我们的示例,接下来我们需要从三个年、月和日属性创建一个 Java Date 对象。 我们还将映射所有其他四个属性并实例化我们完整的 Java 模型:

// 更改特定类型的序列化
JsonDeserializer<UserDate> deserializer = new 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
        );
    }
};

正如我们在上面看到的,我们调用 getAsJsonObject() 来访问更方便的 JsonElement 包装。 然后我们可以调用 get() 来访问模型属性的值。 我们可以根据类型使用各种方法访问该模型属性的值,例如 getAsBoolean()。 最后,我们返回 UserDate 类的一个新实例。

根据数据的保证,我们可能需要使用 has() 检查 JsonObject 中是否存在模型属性。 否则,如果大家正在访问一个属性然后尝试获取它的值,则可能会遇到 NullPointerExceptions

总结

在这篇文章中,我们了解了如何自定义 Gson 反序列化。 调整一次映射通常比在整个应用程序中处理奇怪的数据格式更容易且更有效。 自定义反序列化可以为我们做到这一点。