2017-06-10 4 views
2

Je n'arrive pas à désérialiser correctement une classe Kotlin imbriquée comme le type correct avec Gson. Lorsque j'essaie de désérialiser la même classe Java, cela fonctionne correctement.Gson avec la classe imbriquée par Kotlin

classe Java:

package example; 

import java.util.List; 
import java.util.Map; 

class TestJsonJava { 
    Map<String, List<Entry>> outer; 

    static class Entry { 
     String inner; 
    } 
} 

classe Kotlin:

package example 

class TestJsonKotlin { 
    var outer: Map<String, List<Entry>>? = null 

    class Entry { 
     var inner: String? = null 
    } 
} 

Kotlin principale:

package example 

import com.google.gson.GsonBuilder 

class Main { 
    companion object { 
     @JvmStatic 
     fun main(args: Array<String>) { 
      val json = """ 
{ 
    "outer": { 
     "keyA": [ 
      { 
       "inner": "hello" 
      } 
     ] 
    } 
} 
""" 
      val javaObject = GsonBuilder().create().fromJson(json, TestJsonJava::class.java) 
      val javaWorks = javaObject.outer!!["keyA"]!![0] is TestJsonJava.Entry 
      println("Java works : $javaWorks") 
      println(javaObject.outer!!["keyA"]!![0].inner) 

      val kotlinObject = GsonBuilder().create().fromJson(json, TestJsonKotlin::class.java) 
      val kotlinWorks = kotlinObject.outer!!["keyA"]!![0] is TestJsonKotlin.Entry 
      println("Kotlin works: $kotlinWorks") 
      println(kotlinObject.outer!!["keyA"]!![0].inner) 
     } 
    } 
} 

Cette impression:

Java works : true 
hello 
Kotlin works: false 
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to example.TestJsonKotlin$Entry 
    at example.Main$Companion.main(TestJsonmain.kt:28) 
    at example.Main.main(TestJsonmain.kt) 

Comment puis-je dire à gson de désérialiser la valeur de keyA en List<Entry> au lieu de LinkedTreeMap?

+0

J'ai remarqué [vous criez beaucoup au compilateur.] (Https://blog.philipphauer.de/idiomatic-kotlin-best-practices/#avoid-not-null-assertions) Je suppose que cette utilisation de '!! 'est juste pour MCVE fins? –

+0

Oui, c'est juste pour l'exemple pour garder les choses simples – nioncode

Répondre

2

Annoter la List avec @JvmSuppressWildcards semble aider:

var outer: Map<String, @JvmSuppressWildcards List<Entry>>? = null 

Si nous n'utilisons @JvmSuppressWildcards, le code Kotlin est traduit à:

Map<String, ? extends List<TestJsonKotlin.Entry>> outer; 

Si nous utilisons puis, le code est traduit en:

Map<String, List<TestJsonKotlin.Entry>> outer; 

La différence est dans le caractère générique ? extends - ceci n'est pas supporté même si vous écrivez ceci en Java. J'ai déposé un problème dans le référentiel de Gson here.


Les javap met en évidence la différence entre les deux cas:

// `TestJsonKotlin` with `val outer` is compiled to 
public final class TestJsonKotlin { 
    private final java.util.Map<java.lang.String, java.util.List<TestJsonKotlin$Entry>> outer; 
    public final java.util.Map<java.lang.String, java.util.List<TestJsonKotlin$Entry>> getOuter(); 
    // ... 
} 

// `TestJsonKotlin` with `var outer` is compiled to 
public final class TestJsonKotlin { 
    private java.util.Map<java.lang.String, ? extends java.util.List<TestJsonKotlin$Entry>> outer; 
    public final java.util.Map<java.lang.String, java.util.List<TestJsonKotlin$Entry>> getOuter(); 
    // ... 
} 

Le cas var ajoute ? extends devant la java.util.List<TestJsonKotlin$Entry>.

+0

Cela ne ressemble pas à un problème de Gson, et cela ressemble vraiment à 'kotlinc' (existe-t-il?) Ne produit pas d'informations de paramétrage pour' var outer'. Que produit 'javap' pour les deux cas,' var' et 'val'? –

+0

Hm, c'est intéressant. Ce serait bien d'avoir l'avis de l'équipe Gson. Je vous remercie! –

+0

'@ JvmSuppressWildcards' semble aider –