Лучший способ преобразования массива JSON в список <T>при наличии KClass <T>через Gson - PullRequest
0 голосов
/ 25 ноября 2018

Я создаю многоплатформенную библиотеку JSON в качестве прототипа, чтобы понять, как структурировать вещи.

В настоящее время у меня есть эта функция расширения для преобразования из массива JSON в список объектов.

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

Реализация этого интерфейса для Джексона довольно проста:

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, кажется, что этот шаблон выглядит следующим образом:

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;

This:

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

где SampleClass - это тип T

Если я удаляю типы и печатаю результатt

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

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

я вижу правильные данные:

[{blah1 = текст, blah2 = 123.0, blah3 = 567.0}, {blah1 = текст, blah2 = 123.0, blah3= 567.0}]

класс java.util.ArrayList

класс java.util.ArrayList

Распечатка первого элемента этого ArrayList, но я вижу, чтоэто не тип SampleClass, а LinkedTreeMap

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

class com.google.gson.internal.LinkedTreeMap

Преобразование каждого элемента в этом списке в строку, а затемпреобразование каждого отдельного двоичного объекта JSON в объекты, кажется, работает, но выглядит очень странно

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?

...