Подтвердить что ты не робот

Как использовать TypeToken + generics с Gson в Kotlin

Я не могу получить список универсального типа из пользовательского класса (Turns):

val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)

он сказал:

cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
4b9b3361

Ответ 1

Создайте эту забавную игру:

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)

и затем вы можете назвать это следующим образом:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

Предыдущие альтернативы:

АЛЬТЕРНАТИВА 1:

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

Вы должны поместить object : и конкретный тип в fromJson<List<Turns>>


АЛЬТЕРНАТИВА 2:

Как упомянуто @cypressious, это может быть достигнуто также следующим образом:

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

использовать как:

val turnsType = genericType<List<Turns>>()

Ответ 2

Это решает проблему:

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

Первая строка создает выражение object, которое происходит от TypeToken, а затем получает Java Type. Тогда методу Gson().fromJson нужен либо тип, указанный для результата функции (который должен соответствовать созданному TypeToken). Две версии этой работы, как указано выше, или:

val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)

Чтобы упростить создание TypeToken, вы можете создать вспомогательную функцию, которая должна быть inline, чтобы она могла использовать параметры типа reified:

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

который затем можно использовать одним из следующих способов:

val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()

И весь процесс может быть завернут в функцию расширения для экземпляра Gson:

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)

Чтобы вы могли просто позвонить Gson и не беспокоиться о TypeToken вообще:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

Здесь Kotlin использует вывод типа с одной стороны задания или другой, и генерирует обобщенные данные для встроенной функции для прохождения через полный тип (без стирания) и используя это для построения TypeToken, а также делает позвонить в Gson

Ответ 3

Другим вариантом (не уверен, что он выглядит более элегантно, чем другие) может быть такой вызов:

turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()

Таким образом, вы используете лайнер java Array class one вместо "pure Kotlin".

Ответ 4

val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
    object : TypeToken<List<SaleItemResponse>>() {}.type)

Это мой способ разбора массива данных в kotlin.

Ответ 5

Это работает также и проще

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)

Ответ 6

Я использовал что-то подобное для преобразования T в string & String вернуться к T с помощью Gson. Не совсем то, что вы ищете, но на всякий случай.

Объявление расширения

inline fun <reified T : Any> T.json(): String = Gson().toJson(this, T::class.java)
inline fun <reified T : Any> String.fromJson(): T = Gson().fromJson(this,T::class.java)

Использование
// Passing an object to new Fragment
companion object {    
        private const val ARG_SHOP = "arg-shop"

        @JvmStatic
        fun newInstance(shop: Shop) =
                ShopInfoFragment().apply {
                    arguments = Bundle().apply {
                        putString(ARG_SHOP, shop.json())
                    }
                }
    }

// Parsing the passed argument
private lateinit var shop: Shop

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            shop = it.getString(ARG_SHOP).fromJson() ?: return
        }
    }