Gson 和 Kotlin Data Class 的避坑指南
2023-12-14 03:45:19
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 如何处理这些特殊类型。