Десериализация классов с ленивыми свойствами с использованием 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' 

Я не могу понять, как это исправить. Есть идеи?

Изменить: свойство lazy сериализуется в JSON ( "my_lazy_prop$delegate":{} ), но это не то, что я хочу, поскольку оно вычисляется из других свойств. Я полагаю, что если я найду способ предотвратить сериализацию свойства, будет устранена авария десериализации.

Поскольку Kotlin 1.0 просто помечает поле, подобное этому, чтобы игнорировать его во время de / serialization:

 @delegate:Transient val field by lazy { ... } 

Причина в том, что поле 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