如何在Kotlin中将TypeToken +泛型与Gson一起使用

How to use TypeToken + generics with Gson in Kotlin

我无法从自定义类(转)获得通用类型的列表:

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

它说:

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

创建此内联乐趣:

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

然后您可以通过以下方式调用它:

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

先前的选择:

替代方案1:

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

您必须将object :和特定类型放入fromJson>

替代方案2:

正如@cypressious提及的那样,也可以通过以下方式实现:

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

用于:

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


这样可以解决问题:

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

第一行创建一个对象表达式,该对象表达式从TypeToken继承,然后从中获取Java Type。然后Gson().fromJson方法要么需要为函数的结果指定类型(应该与创建的TypeToken匹配)。此作品的两个版本,如上所述或:

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

为了使创建TypeToken更加容易,您可以创建一个辅助函数,该函数必须是内联的,以便可以使用经过修饰的类型参数:

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

然后可以通过以下两种方式之一使用它:

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

整个过程可以包装到Gson实例的扩展函数中:

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

这样您就可以致电Gson而不用担心TypeToken

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

Kotlin在这里使用的是从赋值一侧或另一侧进行类型推断,并对内联函数使用泛型泛型来传递完整类型(不删除),并使用该泛型构造一个TypeToken并调用Gson


另一个选择(不确定它看起来比其他选择更优雅)可能是这样的调用:

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

因此,您使用的是Java Array类的一个内衬而不是" pure Kotlin"。


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

这是我在Kotlin中解析数据数组的方式。


我使用类似的方法使用GsonT转换为string并将string转换回T。并非完全符合您的要求,以防万一。

Declaring extension

1
2
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)

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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
        }
    }

这同样有效,并且更简单

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