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


108

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

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

它说:

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

Answers:


236

创建此内联乐趣:

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

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

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

先前的选择:

替代方案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>>()

4
您也可以创建一个可以帮助您的帮助方法:inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Kirill Rakhman 2015年

1
甚至扩展Gson以使其具有fromJson的新重载。Kotlin旨在进行扩展,因此扩展Gson使其更美观并隐藏TypeTokens。
杰森·米纳德

我进行了建议的编辑,使答案更加完整和正式,因为使用Gson的许多人都可能看到此答案。我在答案中添加了解释,并链接到Kotlin参考资料中用于解决问题的主题...因此,人们不必阅读与此相关的所有其他答案或评论。如果您接受修改,则可以在下面删除我的答案。
杰森·米纳德

编辑被拒绝,请参阅下面的完整版本,将所有答案和评论合并为一个连贯的答案。您接受了自己的答案,但还不完整。
杰森·米纳德

删除kotlin警告:内联有趣<reified T> genericType():类型?=对象:TypeToken <T>(){} .type
Juan Mendez

28

这样可以解决问题:

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

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

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

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

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)

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


1
@Jayson,您好,我无法使其在Android Studio中实现内联乐趣。似乎还可以,但是我不能认出来Gson().fromJson<kotlin.List<Turns>>(pref.turns)
Juan Saravia

@juancho您能给我打电话“不被认可”是什么意思吗?编译器错误?您已经导入了扩展方法并且可以从上面使用?
杰森·米纳德

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

这与Android Studio没有直接关系,Kotlin的内部或外部都是相同的。您是在创建静态实例Gson()还是Gson静态实例?您需要第一个实例。
杰森·米纳德

21

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

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

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


2
由于TypeToken不能在所有可靠的手机上正常工作,因此这对我来说是最佳的解决方案。一个简单的衬里与纯kotlin。
LuckyMalaka '18

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

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


这应该是公认的答案,简短而简单。
Umar Ata

6

我使用了类似这样的方法来转换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)

用法

// 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
        }
    }

5

这同样有效,并且更简单

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

返回类型必须为可为空。否则,Gson库中的Java代码可以返回null,但是Kotlin假定该类型为不可为空。结果,您在Kotlin获得了NPE。
fdermishin

1

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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.