这几天在对接某项目时,碰到了个关于Kotlin Serialization的小问题,一般来说,我们把对象序列化成JSON,或者JSON串转成对象,Google Gson用的比较多.但对于Kotlin来说,Gson反序列化时出现了问题.
准备类:
data class A(var b: Int , var c: String = "kotlin")
测试及结果:
val gson = Gson()
println("this gson for json to object ${gson.fromJson<A>("{\"b\":\"1\"}" , A::class.java)}")
this gson for json to object A(b=1, c=null)
属性c的默认值:"kotlin"给转成null了!!!后来测试很多次,都是这种情况,那么咱就可以简单的下个结论:gson反序列化时不认识kotlin的默认值.接下来咱就探索下gson机制和kotlin default value.
gson机制:
我们深入追究其源码发现核心工具是TypeAdapter,这是Gson虚拟基类,提供了序列化(write)和反序列化(read)方法(如有研究需要可继续深究ReflectiveTypeAdapterFactory创建TypeAdapter实例,这里暂不做赘述).read是读取Json中的属性信息,解析Json键值对,根据键名找到对象中对应的字段;循环Json直至值全部是基本类型则终止.这就为我们提供了解析json串:{"b":1}的依据,找不到属性c.
kotlin default value:
即使是我们在构造器中给出了默认值,但gson依然不认识,他更不会调用我们自定义的构造器.我们给准备类A加上初始化值以证明我们的结论.
data class A(var b: Int , var c: String = "kotlin") {
private var a: Long = 1
override fun toString(): String {
return "A(b=$b, c='$c', a=$a)"
}
}
测试结果:
this gson for json to object A(b=1, c='null', a=0)
a的初始化值1并没有被赋值 ;我们对此进行其他拓展,看看gson是否对属性代理进行反序列化操作,对上述代码做更改:
data class A(var b: Int , var c: String = "kotlin") {
private var a: String = "kotlinx"
val d by lazy { a[0] }
override fun toString(): String {
return "A(b=$b, c='$c', a=$a,d=$d)"
}
}
测试结果:
Exception in thread "main" java.lang.NullPointerException
即使是d参与了序列化,gson也不会处理,会直接抛出NPE.所谓的属性代理会产生一个内部代理属性,我们去访问d时实际上是获取d的getValue方法,而该属性并没有正常初始化,故而抛出了NPE.
上述是gson在兼容kotlin序列化时所产生的问题,在这方面kotlin给出了解决方案:kotlinx.serialization框架 ,下一篇我们要实战该框架,解决我们开发过程中遇到的问题.
用前准备:
kotlinx.serialization框架目前还在仓库中,查看最新版本,需注意该框架对kotlin有版本要求:version "1.2.60"及以上版本可用.maven仓库地址:maven ("https://kotlin.bintray.com/kotlinx");序列化插件: classpath("org.jetbrains.kotlinx:kotlinx-gradle-serialization-plugin:0.6.1");运行时插件:compile("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.6.1").仍然在用Groovy的,请移步至GitHub.如有出现下面问题的,请仔细检查gradle插件依赖及版本是否正确.