Android Kotlin - Generics в GSON JsonDeserializer для работы с массивом против Obj - PullRequest
0 голосов
/ 24 апреля 2019

Мне нужен наш анализатор GSON, чтобы иметь возможность обрабатывать массив против отдельных объектов.У меня это работает, где он распознает любой MutableList и попадает в адаптер Deserializer ниже.Тем не менее, мне не хватает фрагмента, в котором ему не нравится тип "T" при выполнении сериализации в объект.Я понимаю, что на данный момент ему нужен тип, но есть ли что-то, чего мне не хватает, чтобы иметь возможность сделать вывод, учитывая то, что у нас здесь?

class JsonArrayObjectAdapter<T>: JsonDeserializer<MutableList<T>> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): MutableList<T> {
        val list = mutableListOf<T>()
        json?.let {
            context?.let {
                if (json.isJsonArray) {
                    for (element in json.asJsonArray) {
                        val obj: T = context.deserialize(element, T::class.java) // does not like this
                        list.add(obj)
                    }
                } else if (json.isJsonObject) {
                    val obj: T = context.deserialize(json, T!!::class.java) // does not like this
                    list.add(obj)
                }
            }
        }
        return list
    }
}

Я получаю эту ошибку компиляции при попытке использовать T::class.java:

Cannot use 'T' as reified type parameter. Use a class instead.

Вот пример класса данных, который я использую для справки:

data class ExampleDataClass(
    @SerializedName("ExampleKey") val exampleVar: MutableList<ExampleSubDataClass>
)

А вот как я создаю gson:

val listType = object : TypeToken<MutableList<ExampleDataSubClass>>() {}.getType()
val gson = GsonBuilder()
        .registerTypeAdapter(listType, JsonArrayObjectAdapter<ExampleDataSubClass>())
        .create()
result = gson.fromJson(jsonString, ExampleDataClass::class.java)

1 Ответ

0 голосов
/ 07 мая 2019

Чтобы это исправить, мне нужно было просто создать несколько адаптеров для каждого типа объекта, который может быть массивом или объектом.К сожалению, так как у меня было около 50 различных типов этих объектов, так что много кода повторения с вызовом «registerTypeAdapters» в GsonBuilder.

Чтобы упростить немного, я сделал универсальный метод для возврата массивана основе заданного JsonElement и универсального T-объекта:

fun <T> getJSONArray(json: JsonElement, type: Type, ctx: 
JsonDeserializationContext): ArrayList<T> {
    val list = ArrayList<T>()
    if (json.isJsonArray) {
        for (e in json.asJsonArray) {
            list.add(ctx.deserialize<Any>(e, type) as T)
        }
    } else if (json.isJsonObject) {
        list.add(ctx.deserialize<Any>(json, type) as T)
    } else {
        throw RuntimeException("Unexpected JSON type: " + json.javaClass)
    }
    return list
}

и примера определения адаптера, использующего вышеуказанный метод:

class JsonArrayObjectAdapterExampleDataClass: JsonDeserializer<ArrayList<ExampleDataClass>> {
    override fun deserialize(json: JsonElement, typeOfT: Type, ctx: JsonDeserializationContext): ArrayList<ExampleDataClass> {
        return getJSONArray(json, ExampleDataClass::class.java, ctx)
    }
}

Он не работает просто для передачиtypeOfT var к методу getJSONArray, так как вместо этого мне пришлось явно отправлять определенный тип.

...