2015-12-23 7 views
14

Mit Gson möchte ich eine Kotlin-Klasse deserialisieren, die eine faule Eigenschaft enthält.Deserialisieren von Klassen mit faulen Eigenschaften mit Gson und Kotlin 1.0 beta 4

Mit Kotlin 1.0 beta 4 bekomme ich folgende Fehler bei der Objekt Deserialisierung:

Caused by: java.lang.InstantiationException: can't instantiate class kotlin.Lazy 

Mit Kotlin 1.0 beta 2, I verwendet, um die Eigenschaft mit dem @Transient annotaiton markieren Gson zu sagen, es zu überspringen. Mit Beta 4 ist dies nicht mehr möglich, da die Annotation einen Kompilierungsfehler verursacht.

This annotation is not applicable to target 'member property without backing field' 

Ich kann nicht herausfinden, wie das zu beheben ist. Irgendwelche Ideen?

Edit: die Lazy-Eigenschaft ist in JSON ("my_lazy_prop$delegate":{}) serialisiert, aber das ist nicht was ich will, wie es von anderen Eigenschaften berechnet wird. Ich nehme an, wenn ich einen Weg finde, zu verhindern, dass die Eigenschaft serialisiert wird, würde der Deserialisierungsabsturz behoben werden.

+0

Würden Sie bitte die Änderung der akzeptierte Antwort auf meins, das ist aktueller und hat mehr Stimmen? –

+1

Sure @FabianZeindl – clemp6r

Antwort

23

Da Kotlin 1.0 einfach markieren Sie das Feld wie diese es während de/Serialisierung zu ignorieren:

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

Der Grund ist, dass das Feld delegate eigentlich kein Hintergrundfeld ist, also wurde es verboten. Eine der Abhilfen implementieren ExclusionStrategy: https://stackoverflow.com/a/27986860/1460833

So etwas:

@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() 

Siehe zugehörigen Ticket https://youtrack.jetbrains.com/issue/KT-10502

Die andere Abhilfe als auch faul Werte zu serialisiert ist:

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") 
} 

Anwendungsbeispiel:

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(c.f) 
} 

, die die folgende Ausgabe erzeugt:

{"f":1,"o":0} 
C(o=0) 
1 
+0

Ich habe deinen Code kopiert, die ExclusionStrategy auf Gson registriert, das Feld "Lazy" mit der Anmerkung @GsonTransient -> no effect markiert. Habe ich etwas verpasst? – clemp6r

+0

Vielleicht haben Sie vergessen, es auf Gson Builder –

+0

Hinweis: f.getAnnotation wird für das Feld aufgerufen, aber Null zurückgegeben – clemp6r

Verwandte Themen