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'
53
demandé sur Juancho 2015-10-28 04:29:08

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>>()
108
répondu Juancho 2017-10-06 16:57:58

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

21
répondu Jayson Minard 2015-12-28 00:18:07

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".

4
répondu Tobias Reich 2018-07-23 18:24:34

Cela fonctionne aussi, et est plus simple

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)
2
répondu Christopher Perry 2017-07-05 20:26:10
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.

1
répondu Toàn Mỹ 2018-04-09 03:31:42

, 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
        }
    }
0
répondu harsh_v 2018-05-09 06:10:46