Gson: Kotlin var does not save generic type (deserialized to LinkedTreeMap instead)

Created on 12 Jun 2017  Â·  11Comments  Â·  Source: google/gson

data class BigClass(var inBig: Map<String, List<SmallClass>>? = null)
data class SmallClass(var inSmall: String? = null)

fun main(args: Array<String>) {
    val json = """
{
    "inBig": {
        "key": [
            { "inSmall": "hello" }
        ]
    }
}
"""

    val deserialized = Gson().fromJson(json, BigClass::class.java)
    println(deserialized.inBig!!["key"]!![0].inSmall) // should print "hello" but throws instead
}

Executing the code above will lead to the following Exception:

Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to SmallClass
    at MyClass.main(MyClass.kt:18)

The List<SmallClass> is actually deserialized to List<LinkedTreeMap>.

However, if I changed the definition of inBig variable to be a constant, then it deserializes just fine:

data class BigClass(val inBig: Map<String, List<SmallClass>>? = null)

I changed var to val and the code prints "hello" as expected.

Kotlin 1.1.1 and Gson 2.8.1.

Most helpful comment

after adding in data class @JvmSuppressWildcards(suppress = true) to problematic field I still get LinkedTreeMap

@JvmSuppressWildcards(suppress = true)
    @SerializedName("patient")
    @Expose
    var patient: Any? = null

All 11 comments

I have run javap on both cases and here are the results:

// `BigClass` with `val inBig` is compiled to
public final class BigClass {
  private final java.util.Map<java.lang.String, java.util.List<SmallClass>> inBig;
  public final java.util.Map<java.lang.String, java.util.List<SmallClass>> getInBig();
  // ...
}

// `BigClass` with `var inBig` is compiled to
public final class BigClass {
  private java.util.Map<java.lang.String, ? extends java.util.List<SmallClass>> inBig;
  public final java.util.Map<java.lang.String, java.util.List<SmallClass>> getInBig();
  // ...
}

The var case adds ? extends in front of the java.util.List<SmallClass>.

Yes, I have same problem, but this issue reproduce only in some devices

yep, you probably want @JvmSuppressWildcards.
https://github.com/google/dagger/issues/668#issuecomment-289713497

Yes, looks like annotating the List with @JvmSuppressWildcards helps:

data class BigClass(var inBig: Map<String, @JvmSuppressWildcards List<SmallClass>>? = null)

Seems like Gson supports wildcard types, though – see #39 and this test.

Also, when using Jackson, it works just fine without an annotation.

I have done some more research and it seems like Kotlin is not at fault. Gson fails with the same exception for the following Java class (which is similar to the Kotlin one in the issue description):

class BigClass {
    Map<String, ? extends List<SmallClass>> inBig;
}

// ...

class SmallClass {
    String inSmall;
}

Closed in favor of #1107.

after adding in data class @JvmSuppressWildcards(suppress = true) to problematic field I still get LinkedTreeMap

@JvmSuppressWildcards(suppress = true)
    @SerializedName("patient")
    @Expose
    var patient: Any? = null

as not worked so and not works, why the problem is considered solved? @egor-n

@abbath0767 this is a duplicate of #1107.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

GoogleCodeExporter picture GoogleCodeExporter  Â·  17Comments

adiantek picture adiantek  Â·  23Comments

GoogleCodeExporter picture GoogleCodeExporter  Â·  19Comments

inder123 picture inder123  Â·  17Comments

GoogleCodeExporter picture GoogleCodeExporter  Â·  20Comments