在 json -> class
时,Gson
只会使用无参构造函数,如果没有他就通过Unsafe
自己创建,不会走其他构造函数。
空安全设计
首先明确一点,Gson
不会管Kotlin
的空安全设计。只要是Json
数据里面指定的是null
的数据,就算你写的是非空最后实例化出来的时候也会是空的。例如:
Kotlin
data class User(
val age: Int = 11,
val name: String = "lucy",
val phone: String = "13888888888"
)
Json
"name" : null
最后实例化出来的user.name = null
,而没有的字段user.phone = 13888888888 user.age = 11
使用data class
的情况
必须保证所有的变量都给了默认值,这样 data class
才有无参构造函数,从而使你定义的默认值有效,如果不是全给,只要是 json
里面没有的,数据类型都为 0 ,布尔型为 false ,其他类型都是 null。例如:
Kotlin
data class User(
val age: Int,
val name: String = "lucy",
val phone: String = "13888888888"
)
Json
"name" : null
由于age
没有给默认值,编译的时候Kotlin
就不会给这个类默认的无参构造函数,Gson
就通过Unsafe
自己创建,也就不会走Kotlin
定义的构造函数去赋值。最后实例化出来的就是:age = 0 , name = null , phone = null
解决办法
1.Moshi
Moshi
倒是能很好的支持Kotlin
的空安全,但是也会有困扰,首先服务器返回的Json
的数据指不定哪个就是null
的,如果你代码里面设定的是非空,那Moshi
就会直接抛异常,不解析了。感觉和实际开发使用有点不合,可能其他数据会有用啊,不能只因为一个异常数据导致所有的都用不了,这些判断应该放在我自己的代码里面我才安心。而且切换库有代价啊!!!
2.安全的写法
data class User(
val age: Int,
@SerializedName("name") private val _name: String?
) {
val name
get() = _name ?: "lucy"
}
像这种你不想他为空,就算是服务器错误的给了一个空值过来,你也要用一个默认值代替,可以这么写。显然,这个解决方案很冗长,如果变量多了那是要写一大把代码,我用data class
不就是图方便吗,当然你不嫌麻烦可以这样写。
使用建议
所以我使用的初步建议就是,让一切都为空!!!
- 定义类的时候必须给所有变量赋默认值,并且非数据类型都设定可空,默认赋值为空;
- 确定
Json
里面不会出现,而是自己加的一些工具属性可以定义默认值。
像这样:
data class User(
val age: Int = 0,
val name: String? = null,
val pay: Boolean = false,
val phone: String = "13888888888"
)