使用Gson和Kotlin 1.0 beta 4反序列化具有惰性属性的类
使用Gson,我想反序列化一个包含懒惰属性的Kotlin类。
Kotlin 1.0 beta 4在对象反序列化过程中出现以下错误:
Caused by: java.lang.InstantiationException: can't instantiate class kotlin.Lazy
用Kotlin 1.0 beta 2,我用@Transient annotaiton来标记属性,告诉Gson跳过它。 随着测试版4,这是不可能的,因为注释导致编译错误。
This annotation is not applicable to target 'member property without backing field'
我无法弄清楚如何解决这个问题。 有任何想法吗?
编辑:懒惰属性序列化为JSON( "my_lazy_prop$delegate":{}
),但这不是我想要的,因为它是从其他属性计算。 我想,如果我找到一种方法来防止财产被序列化,反序列化崩溃将被修复。
原因是delegate
字段实际上并不是一个支持字段,因此被禁止。 其中一个解决方法是实施ExclusionStrategy
: https : //stackoverflow.com/a/27986860/1460833
类似的东西:
@Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) annotation class GsonTransient object TransientExclusionStrategy : ExclusionStrategy { override fun shouldSkipClass(type: Class<*>): Boolean = false override fun shouldSkipField(f: FieldAttributes): Boolean = f.getAnnotation(GsonTransient::class.java) != null || f.name.endsWith("\$delegate") } fun gson() = GsonBuilder() .setExclusionStrategies(TransientExclusionStrategy) .create()
请参阅相关票https://youtrack.jetbrains.com/issue/KT-10502
另一个解决方法是序列化惰性值以及:
object SDForLazy : JsonSerializer<Lazy<*>>, JsonDeserializer<Lazy<*>> { override fun serialize(src: Lazy<*>, typeOfSrc: Type, context: JsonSerializationContext): JsonElement = context.serialize(src.value) override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Lazy<*> = lazyOf<Any?>(context.deserialize(json, (typeOfT as ParameterizedType).actualTypeArguments[0])) } class KotlinNamingPolicy(val delegate: FieldNamingStrategy = FieldNamingPolicy.IDENTITY) : FieldNamingStrategy { override fun translateName(f: Field): String = delegate.translateName(f).removeSuffix("\$delegate") }
用法示例:
data class C(val o: Int) { val f by lazy { 1 } } fun main(args: Array<String>) { val gson = GsonBuilder() .registerTypeAdapter(Lazy::class.java, SDForLazy) .setFieldNamingStrategy(KotlinNamingPolicy()) .create() val s = gson.toJson(C(0)) println(s) val c = gson.fromJson(s, C::class.java) println(c) println(cf) }
这将产生以下输出:
{"f":1,"o":0} C(o=0) 1
由于Kotlin 1.0只是将这个字段标记为de / serialization时忽略它:
@delegate:Transient val field by lazy { ... }