Kotlin中使用Gson解析泛型T遇类型转换异常如何解决?
这个问题我之前做项目时也踩过坑!罪魁祸首是Java/Kotlin的类型擦除机制——当你在泛型类里写object : TypeToken<T>() {}.type时,编译阶段泛型参数T的具体类型会被擦除,Gson根本不知道要解析成com.example.model.content,只能默认转成LinkedTreeMap,这就直接抛出了类型转换异常。
下面给你几种靠谱的解决办法,根据你的场景选就行:
方案1:用Kotlin的inline reified特性(推荐,最简洁)
如果是Kotlin环境,把解析逻辑封装成inline reified函数。这种特性会让编译器在调用函数时,把实际的类型信息传递进去,完美绕过类型擦除:
// 顶层函数或者工具类函数 inline fun <reified T> parseJsonToType(jsonStr: String): T { return Gson().fromJson(jsonStr, object : TypeToken<T>() {}.type) } // 调用的时候直接指定具体类型 val content = parseJsonToType<com.example.model.content>(jsonStr)
如果你的解析逻辑必须放在泛型类里,也可以把解析函数改成inline reified的成员函数,但注意类本身的泛型T还是会被擦除,调用时必须显式指定具体类型。
方案2:在类构造时传入Type或TypeToken
因为泛型类本身无法保留T的实际类型信息,所以可以在创建类实例的时候,把T的类型信息主动传进去:
class DataParser<T>(private val targetType: Type) { fun parse(jsonStr: String): T { return Gson().fromJson(jsonStr, targetType) } } // 创建实例时传入具体的TypeToken类型 val parser = DataParser<com.example.model.content>(object : TypeToken<com.example.model.content>() {}.type) val content = parser.parse(jsonStr)
也可以直接传入TypeToken对象,代码更清晰:
class DataParser<T>(private val typeToken: TypeToken<T>) { fun parse(jsonStr: String): T { return Gson().fromJson(jsonStr, typeToken.type) } } // 调用方式 val parser = DataParser(object : TypeToken<com.example.model.content>() {}) val content = parser.parse(jsonStr)
方案3:传递Class<T>(适合非泛型实体类)
如果你的T是普通的实体类(不是List<T>这种带泛型的复合类型),可以直接传递Class对象,写法更简单:
class DataParser<T>(private val clazz: Class<T>) { fun parse(jsonStr: String): T { return Gson().fromJson(jsonStr, clazz) } } // 创建实例时传入Class val parser = DataParser(com.example.model.content::class.java) val content = parser.parse(jsonStr)
⚠️ 注意:这个方法只适用于非泛型类型,如果T是List<com.example.model.content>这类带泛型的类型,Class对象无法保留泛型信息,还是会解析成List<LinkedTreeMap>,导致类型转换异常。
核心思路总结
不管用哪种方案,核心都是绕过类型擦除,让Gson在运行时能拿到T的实际类型信息。Kotlin的inline reified是最方便的方式,而如果是Java环境或者必须在泛型类中处理,就通过构造函数传入Type或TypeToken来保留类型信息。
内容的提问来源于stack exchange,提问作者lannyf

