Comment utiliser typetoken + generics avec Gson dans Kotlin
Je ne peux pas obtenir une liste de type générique à partir d'une classe personnalisée (tourne):
val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
Il a dit:
cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
6 réponses
Créez ce plaisir en ligne:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
, puis vous pouvez l'appeler de cette façon:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
NOTE : cette approche n'était pas possible auparavant dans les anciennes versions du plugin kotlin, mais maintenant vous pouvez l'utiliser.
Variantes Précédentes:
Variante 1:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
, Vous devez mettre object :
et le type spécifique de fromJson<List<Turns>>
Variante 2:
Comme @ cypressious mention, il peut être réalisé aussi dans ce façon:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Utiliser comme:
val turnsType = genericType<List<Turns>>()
Cela résout le problème:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
La première ligne crée une expression d'objet qui descend de TypeToken
et obtient ensuite le Java Type
à partir de cela. Ensuite, la méthode Gson().fromJson
nécessite soit le type spécifié pour le résultat de la fonction(qui doit correspondre au TypeToken
Créé). Deux versions de ce travail, comme ci-dessus ou:
val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
Pour faciliter la création du TypeToken
, Vous pouvez créer une fonction d'assistance, qui doit être inline afin qu'elle puisse utiliser paramètres de type réifié :
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Qui peut alors être utilisé de l'une ou l'autre de ces manières:
val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()
Et l'ensemble du processus peut être enveloppé dans une fonction d'extension de la Gson
exemple:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
De sorte que vous pouvez simplement appeler Gson et ne pas vous soucier du TypeToken
du tout:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Ici, Kotlin utilise l'inférence de type d'un côté de l'affectation ou de l'autre, et des génériques réifiés pour qu'une fonction en ligne passe par le type complet (sans effacement), et en utilisant cela pour construire un TypeToken
et aussi faire L'appel à Gson
Une autre option (pas sûr qu'il semble plus élégant que les autres) pourrait être un appel comme ceci:
turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()
Vous utilisez donc le liner java Array class one au lieu de "pure Kotlin".
Cela fonctionne aussi, et est plus simple
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)
C'est ma façon d'analyser le tableau de données dans kotlin.
, j'ai utilisé quelque chose comme cela pour convertir T
pour string
& String
retour à la T
utiliser Gson
. Pas exactement ce que vous cherchez, mais juste au cas où.
Déclarer l'extension
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)
Utilisation
// 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
}
}