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

Jua*_*via 87 generics gson kotlin typetoken

我无法从自定义类(Turns)获取泛型类型列表:

val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
Run Code Online (Sandbox Code Playgroud)

它说:

cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
Run Code Online (Sandbox Code Playgroud)

Jua*_*via 191

创建这个内联乐趣:

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
Run Code Online (Sandbox Code Playgroud)

然后你可以用这种方式调用它:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Run Code Online (Sandbox Code Playgroud)

注意:此方法在旧的kotlin插件版本之前是不可能的,但现在您可以使用它.


以前的替代品:

替代方案1:

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

你必须把object :特定的类型放入fromJson<List<Turns>>


替代方案2:

正如@cypressious提到它也可以通过这种方式实现:

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Run Code Online (Sandbox Code Playgroud)

用于:

val turnsType = genericType<List<Turns>>()
Run Code Online (Sandbox Code Playgroud)

  • 你也可以创建一个帮助你的方法:`inline fun <reified T> genericType()= object:TypeToken <T>(){} .type` (3认同)

Jay*_*ard 27

这解决了这个问题:

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

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

val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
Run Code Online (Sandbox Code Playgroud)

为了更容易创建,TypeToken您可以创建一个辅助函数,该函数需要内联,以便它可以使用具体的类型参数:

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Run Code Online (Sandbox Code Playgroud)

然后可以使用以下任何一种方式:

val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()
Run Code Online (Sandbox Code Playgroud)

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

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
Run Code Online (Sandbox Code Playgroud)

这样你就可以打电话给Gson而不用担心TypeToken这一点:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Run Code Online (Sandbox Code Playgroud)

在这里,Kotlin使用从赋值的一方或另一方使用类型推断,并使用内联函数的reified泛型来传递完整类型(没有擦除),并使用它来构造一个TypeToken并且还调用Gson

  • 我将您的代码复制并粘贴到Android Studio中,并将乐趣导入了我的kotlin类。我试图按照您说的去做,但是由于某种原因,编译器告诉我这种乐趣不存在。我已经在使用其他扩展功能,但是我不知道您的建议不起作用。您正在使用哪个版本的AS和Kotlin?只是再试一次。 (2认同)

Tob*_*ich 18

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

turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()
Run Code Online (Sandbox Code Playgroud)

所以你使用的是java Array类,而不是"纯Kotlin".

  • 由于TypeToken不能在每台手机上都可靠,这对我来说是最好的解决方案.一个简单的衬垫与纯kotlin. (2认同)

小智 9

val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
    object : TypeToken<List<SaleItemResponse>>() {}.type)
Run Code Online (Sandbox Code Playgroud)

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


Mos*_*van 7

generic reified functionGson的Kotlin反序列化ArrayList<T>使用这段代码

 inline fun <reified T> get( ... ): ArrayList<T>{
    
    val str = "[{},{}]"
    
    val type = TypeToken.getParameterized(ArrayList::class.java, T::class.java).type
    
    val t = Gson().fromJson<ArrayList<T>>(str, type)
    

    return t
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*rry 5

这同样有效,并且更简单

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)
Run Code Online (Sandbox Code Playgroud)


har*_*h_v 5

我使用了类似这样的东西来转换TstringString回到Tusing 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)
Run Code Online (Sandbox Code Playgroud)

用法

// 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
        }
    }
Run Code Online (Sandbox Code Playgroud)