Как использовать typetoken + дженерики с Gson в Котлине
Я не могу получить список универсального типа из пользовательского класса (по очереди):
val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
Он сказал:
cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
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а затем получает JavaTypeот этого. Тогда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