通过Gson在给定KClass <t>的情况下将JSON数组转换为List <t>的更好方法

时间:2018-11-25 13:03:55

标签: generics kotlin gson kotlin-reflect kotlin-multiplatform

我正在构建一个多平台JSON库作为原型,以了解如何构造事物。

当前,我具有此扩展功能,可以将JSON数组转换为对象列表。

inline fun <reified T : Any> String.fromJsonList() : List<T> = 
    provider.fromJsonList(this, T::class)

为Jackson实施此界面非常简单:

class JvaasJackson : JsonProvider {

    val mapper = ObjectMapper();

    ...

    override fun <T : Any> fromJsonList(input: String, type: KClass<T>): List<T> {
        return mapper.readValue(input, mapper.typeFactory.constructCollectionType(List::class.java, type.java)) ?: listOf()
    }

}

现在我正在尝试与Gson做完全相同的事情:

class JvaasGson : JsonProvider {

    val gsonNormal = com.google.gson.Gson()
    val gsonPretty = com.google.gson.GsonBuilder().setPrettyPrinting().create()

    ...

    override fun <T : Any> fromJsonList(input: String, type: KClass<T>): List<T> {

        TODO("fix this")

    }

}

看看Java中的other answers,这似乎是遵循的模式:

Type listType = new TypeToken<List<MyModel>>(){}.getType();
List<MyModel> myModelList = gson.fromJson(jsonArray, listType);

我的Kotlin等效项失败:

val listType = object : TypeToken<List<T>>() {}.type
val myModelList = gsonNormal.fromJson<List<T>>(input, listType) ?: listOf()

具有:

  

java.lang.ClassCastException:无法将java.util.ArrayList强制转换为   [Ljava.lang.Object;

此:

val listType = object : TypeToken<ArrayList<T>>() {}.type
val myModelList = gsonNormal.fromJson(input, listType) as ArrayList<T>

这:

val listType = object : TypeToken<ArrayList<T>>() {}.type
val myModelList = gsonNormal.fromJson<ArrayList<T>>(input, listType)

失败:

  

java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap   无法转换为io.jvaas.integration.gson.SampleClass

其中SampleClassT的类型

如果我删除类型并打印结果

    val listType = object : TypeToken<ArrayList<T>>() {}.type
    val list= gsonNormal.fromJson<Any>(input, listType)

    println(list)
    println(list::class)
    println(list::class.java)

我看到正确的数据:

  

[{blah1 = text,blah2 = 123.0,blah3 = 567.0},{blah1 = text,blah2 = 123.0,   blah3 = 567.0}]

     

java.util.ArrayList类

     

java.util.ArrayList类

打印出该ArrayList的第一项,但是我看到它不是SampleClass类型,而是LinkedTreeMap

println((list as List<T>).first()::class)
  

com.google.gson.internal.LinkedTreeMap类

将该列表中的每个项目转换为String,然后将JSON的每个单独的blob转换为对象似乎可行,但是看起来很hacky

override fun <T : Any> fromJsonList(input: String, type: KClass<T>): List<T> {

    val listType = object : TypeToken<ArrayList<*>>() {}.type
    val list= gsonNormal.fromJson<List<Any>>(input, listType) ?: listOf<Any>()

    val results = mutableListOf<T>()
    list.forEach { item ->
        results.add(gsonNormal.fromJson(item.toString(), type.java))
    }

    return results

}

是否有更好的方法? 还是Gson总是将更复杂的JSON数据转换为TreeMaps和LinkedTreeMaps?

0 个答案:

没有答案