为何Gson的fromJson需用TypeToken?两种Kotlin实现可行性分析
DTO转领域层的Gson映射函数问题解答
两种Kotlin内联泛型扩展实现
实现一(使用TypeToken)
inline fun <reified DTO_TYPE, reified TYPE> DTO_TYPE.toDomainLayer(): TYPE { val gson = Gson() val strJson = gson.toJson(this) val type = object: TypeToken<TYPE>() {}.type return gson.fromJson(strJson, type) }
实现二(直接用TYPE::class.java)
inline fun <reified DTO_TYPE, reified TYPE> DTO_TYPE.toDomainLayer(): TYPE { val gson = Gson() val strJson = gson.toJson(this) return gson.fromJson(strJson, TYPE::class.java) }
实现二的可用范围
实现二在目标类型TYPE是无泛型参数的普通类时可以正常工作,比如将UserDTO映射到普通数据类User,此时TYPE::class.java能提供足够的类型信息让Gson完成解析。
实现二的失效场景
当TYPE包含泛型参数时,实现二会因为丢失泛型信息而解析失败,典型场景包括:
- 泛型集合类:比如
List<User>、Map<String, Order>。TYPE::class.java只能得到List.class或Map.class,无法获取泛型参数User、Order的类型,Gson会把集合元素解析成默认的LinkedTreeMap,后续类型转换时会抛出异常。 - 自定义泛型类:比如
ApiResult<Data>这类自定义泛型容器。ApiResult::class.java无法携带Data的类型信息,Gson无法正确解析泛型字段,导致目标对象的泛型属性类型错误。
为什么需要TypeToken?
Java和Kotlin都存在泛型类型擦除:编译时泛型信息会被抹除,运行时无法直接获取泛型参数的具体类型。而TypeToken通过创建匿名子类的方式,在编译阶段把完整的泛型类型(包括泛型参数)保留在子类的Class信息中,Gson通过反射读取这个Type对象,就能准确识别目标类型的泛型结构,从而正确解析JSON到带泛型的目标对象中。
内容的提问来源于stack exchange,提问作者Parth Malaviya
相关产品推荐
相关产品推荐

