Как использовать typetoken + дженерики с Gson в Котлине



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



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


Он сказал:



cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
911   6  

6 ответов:

создать эту встроенную забаву:

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)

Примечание: этот подход был невозможен раньше в старых версиях плагинов kotlin, но теперь вы можете его использовать.


Предыдущие Варианты:

альтернатива 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>>()

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

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

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

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

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

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)

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

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

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

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

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

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)
val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
    object : TypeToken<List<SaleItemResponse>>() {}.type)

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

я использовал что-то вроде этого для преобразования 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
        }
    }

Comments

    Ничего не найдено.