返回

Gson 和 Kotlin Data Class 的避坑指南

Android

1. Gson 默认不序列化和反序列化私有字段

当我们使用 Gson 序列化和反序列化 Kotlin Data Class 时,Gson 默认不会处理私有字段。

例如,我们定义了一个如下所示的 Data Class:

data class Person(val name: String, private val age: Int)

如果我们使用 Gson 序列化这个 Data Class:

val gson = Gson()
val json = gson.toJson(Person("John", 30))

那么,序列化的结果将是:

{"name":"John"}

如你所见,私有字段 age 没有被序列化。

如果我们想要序列化和反序列化私有字段,需要显式地告诉 Gson。我们可以使用 @Expose 注解来标记需要序列化的私有字段:

data class Person(@Expose val name: String, @Expose private val age: Int)

现在,使用 Gson 序列化这个 Data Class,将得到以下结果:

{"name":"John","age":30}

2. Gson 默认不会序列化和反序列化枚举类

当我们使用 Gson 序列化和反序列化 Kotlin Data Class 时,Gson 默认不会处理枚举类。

例如,我们定义了一个如下所示的 Data Class:

data class Person(val name: String, val gender: Gender)

enum class Gender {
    MALE,
    FEMALE
}

如果我们使用 Gson 序列化这个 Data Class:

val gson = Gson()
val json = gson.toJson(Person("John", Gender.MALE))

那么,序列化的结果将是:

{"name":"John"}

如你所见,枚举类 Gender 没有被序列化。

如果我们想要序列化和反序列化枚举类,需要显式地告诉 Gson。我们可以使用 @SerializedName 注解来标记枚举类的名称:

enum class Gender {
    @SerializedName("male")
    MALE,

    @SerializedName("female")
    FEMALE
}

现在,使用 Gson 序列化这个 Data Class,将得到以下结果:

{"name":"John","gender":"male"}

3. Gson 默认不会序列化和反序列化泛型类

当我们使用 Gson 序列化和反序列化 Kotlin Data Class 时,Gson 默认不会处理泛型类。

例如,我们定义了一个如下所示的 Data Class:

data class List<T>(val items: List<T>)

如果我们使用 Gson 序列化这个 Data Class:

val gson = Gson()
val json = gson.toJson(List(listOf("John", "Mary")))

那么,序列化的结果将是:

{"items":[]}

如你所见,泛型参数 T 没有被序列化。

如果我们想要序列化和反序列化泛型类,需要显式地告诉 Gson。我们可以使用 @TypeAdapter 注解来指定一个类型适配器。

例如,我们可以定义如下所示的类型适配器:

class ListTypeAdapter<T> : TypeAdapter<List<T>>() {

    override fun write(out: JsonWriter, value: List<T>?) {
        out.beginArray()
        value?.forEach {
            out.value(it)
        }
        out.endArray()
    }

    override fun read(reader: JsonReader): List<T> {
        val list = mutableListOf<T>()
        reader.beginArray()
        while (reader.hasNext()) {
            list.add(reader.nextString())
        }
        reader.endArray()
        return list
    }
}

然后,我们可以在 Data Class 上使用 @TypeAdapter 注解来指定这个类型适配器:

data class List<T>(@TypeAdapter(ListTypeAdapter::class) val items: List<T>)

现在,使用 Gson 序列化这个 Data Class,将得到以下结果:

{"items":["John","Mary"]}

4. Gson 默认不会序列化和反序列化嵌套类

当我们使用 Gson 序列化和反序列化 Kotlin Data Class 时,Gson 默认不会处理嵌套类。

例如,我们定义了一个如下所示的 Data Class:

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

data class Address(val street: String, val city: String)

如果我们使用 Gson 序列化这个 Data Class:

val gson = Gson()
val json = gson.toJson(Person("John", Address("Main Street", "New York")))

那么,序列化的结果将是:

{"name":"John"}

如你所见,嵌套类 Address 没有被序列化。

如果我们想要序列化和反序列化嵌套类,需要显式地告诉 Gson。我们可以使用 @SerializedName 注解来标记嵌套类的名称:

data class Person(val name: String, @SerializedName("address") val address: Address)

data class Address(@SerializedName("street") val street: String, @SerializedName("city") val city: String)

现在,使用 Gson 序列化这个 Data Class,将得到以下结果:

{"name":"John","address":{"street":"Main Street","city":"New York"}}

5. Gson 默认不会序列化和反序列化抽象类

当我们使用 Gson 序列化和反序列化 Kotlin Data Class 时,Gson 默认不会处理抽象类。

例如,我们定义了一个如下所示的 Data Class:

abstract class Person {
    val name: String
}

data class Employee(override val name: String, val salary: Double) : Person()

如果我们使用 Gson 序列化这个 Data Class:

val gson = Gson()
val json = gson.toJson(Employee("John", 3000.0))

那么,序列化的结果将是:

{"name":"John"}

如你所见,抽象类 Person 没有被序列化。

如果我们想要序列化和反序列化抽象类,需要显式地告诉 Gson。我们可以使用 @JsonAdapter 注解来指定一个类型适配器。

例如,我们可以定义如下所示的类型适配器:

@JsonAdapter(PersonTypeAdapter::class)
abstract class Person {
    val name: String
}

class PersonTypeAdapter : TypeAdapter<Person>() {

    override fun write(out: JsonWriter, value: Person?) {
        out.beginObject()
        out.name("name").value(value?.name)
        out.endObject()
    }

    override fun read(reader: JsonReader): Person {
        val name = reader.nextString()
        return Employee(name, 3000.0)
    }
}

data class Employee(override val name: String, val salary: Double) : Person()

现在,使用 Gson 序列化这个 Data Class,将得到以下结果:

{"name":"John","salary":3000.0}

结语

在使用 Gson 和 Kotlin Data Class 进行数据序列化和反序列化时,需要注意一些常见的坑。这些坑包括:

  • Gson 默认不序列化和反序列化私有字段
  • Gson 默认不会序列化和反序列化枚举类
  • Gson 默认不会序列化和反序列化泛型类
  • Gson 默认不会序列化和反序列化嵌套类
  • Gson 默认不会序列化和反序列化抽象类

为了避免这些坑,我们可以显式地告诉 Gson 如何处理这些特殊类型。