Лучший способ преобразования массива JSON в список<T> с помощью KClass<T> через Gson
Я создаю мультиплатформенную библиотеку 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);
Мой котлинский эквивалент терпит неудачу:
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
где SampleClass
это тип 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)
класс 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?