【问题标题】:Gson with Kotlin nested classGson 与 Kotlin 嵌套类
【发布时间】:2017-06-10 10:41:20
【问题描述】:

我无法使用 Gson 将嵌套的 Kotlin 类正确反序列化为正确的类型。 当我尝试反序列化同一个 Java 类时,它工作正常。

Java 类:

package example;

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

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

    static class Entry {
        String inner;
    }
}

Kotlin 类:

package example

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

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

Kotlin 主要:

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

打印出来:

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)

如何告诉 gson 将 keyA 的值反序列化为 List&lt;Entry&gt; 而不是 LinkedTreeMap

【问题讨论】:

标签: gson deserialization kotlin


【解决方案1】:

@JvmSuppressWildcards 注释List 似乎有帮助:

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

如果我们不使用@JvmSuppressWildcards,那么Kotlin代码会被翻译成:

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

如果我们确实使用它,那么代码会被翻译成:

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

不同之处在于通配符? extends - 即使您用Java 编写它也不支持。我在 Gson 的存储库 here 中提交了一个问题。


javap 突出了两种情况的区别:

// `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();
  // ...
}

var 案例在java.util.List&lt;TestJsonKotlin$Entry&gt; 前面添加? extends

【讨论】:

  • 这看起来不像是 Gson 问题,而且听起来确实像 kotlinc(它存在吗?)不会为 var outer 生成参数化信息。 javap 两种情况下的输出是什么,varval
  • 嗯,这很有趣。很高兴获得 Gson 团队的反馈。谢谢!
  • @JvmSuppressWildcards 似乎有帮助
  • 很好的发现。我希望 javap 输出保留在您的答案中,以突出调查过程 - 这可以解释为什么该注释有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多