返回

Gson反序列化时,引用类型的字段缺失处理

Android

Gson 是一个功能强大的 Java 库,用于将 Java 对象序列化为 JSON,以及将 JSON 反序列化为 Java 对象。它提供了许多有用的功能,包括将 Java 对象序列化为 JSON、将 JSON 反序列化为 Java 对象,以及将 JSON 解析为 Java 对象树。

然而,当 Gson 反序列化生成一个 DataClass 时,如果字段缺失,引用类型都会为 null。这在使用非空类型时可能会产生不可预期的后果,因为非空类型的初衷是让程序更健壮,但现在却使程序产生不可预估的后果。

本文将记录探索 Gson 支持 DataClass 的过程,并提供一种处理引用类型字段缺失的方案。

背景

DataClass 是 Kotlin 中的一种特殊类,它允许你轻松地创建具有特定属性的不可变类。DataClass 的主要好处是它们可以自动生成许多有用的方法,包括 equals(), hashCode(), toString()copy()

然而,当 Gson 反序列化生成一个 DataClass 时,如果字段缺失,引用类型都会为 null。这在使用非空类型时可能会产生不可预期的后果,因为非空类型的初衷是让程序更健壮,但现在却使程序产生不可预估的后果。

探索 Gson 对 DataClass 的支持

为了探索 Gson 对 DataClass 的支持,我们首先创建了一个简单的 DataClass:

data class Person(
    val name: String,
    val age: Int,
    val address: Address?
)

然后,我们使用 Gson 将一个 JSON 字符串反序列化为一个 Person 对象:

val json = """
    {
        "name": "John Doe",
        "age": 30
    }
"""

val person = Gson().fromJson(json, Person::class.java)

正如我们所料,person.address 为 null。这是因为 JSON 字符串中没有 address 字段。

处理引用类型字段缺失

为了处理引用类型字段缺失的情况,我们可以使用 Gson 的 @JsonAdapter 注解。此注解允许我们指定一个自定义的适配器,该适配器将用于序列化和反序列化给定的类型。

对于我们的 Person 类,我们可以创建一个自定义适配器来处理 address 字段的缺失:

@JsonAdapter(PersonAdapter::class)
data class Person(
    val name: String,
    val age: Int,
    val address: Address?
)
class PersonAdapter : TypeAdapter<Person>() {

    override fun write(out: JsonWriter, value: Person) {
        out.beginObject()
        out.name("name").value(value.name)
        out.name("age").value(value.age)
        if (value.address != null) {
            out.name("address").value(value.address)
        }
        out.endObject()
    }

    override fun read(reader: JsonReader): Person {
        reader.beginObject()
        var name: String? = null
        var age: Int? = null
        var address: Address? = null
        while (reader.hasNext()) {
            when (reader.nextName()) {
                "name" -> name = reader.nextString()
                "age" -> age = reader.nextInt()
                "address" -> address = reader.nextString()
            }
        }
        reader.endObject()
        return Person(name ?: "", age ?: 0, address)
    }
}

此适配器将检查 address 字段是否存在。如果存在,它将被反序列化为一个 Address 对象。如果不存在,则 address 将保持为 null。

结论

通过使用自定义的 Gson 适配器,我们可以处理引用类型字段缺失的情况。这使我们能够使用非空类型来创建更健壮的程序,同时避免因字段缺失而导致的不可预期的后果。