记一次在 Kotlin 中使用 Gson 序列化 List 带泛型的问题
前言
这个问题花了我 3 个小时,在 Kotlin 中使用 Gson 序列化 List,原本看起来再普通不过的需求,里面却隐藏着一些坑。在 Gson 中,序列化 List<Pojo>
这类实体是没有任何问题的,不用做任何特殊处理即可完成。但如果你序列化的是 List<Pojo<out BasePojo>>
,那么问题就出现了,Pojo 对象本身是有属性和值的,但序列化出来的内容就成这样了 [{},{}]
,对象里面的属性都没了。 仅仅是定义的差别,List 中元素都是完全一样的,为啥一个可以一个不行呢?
怎么解决
网上查阅资料较少,基本没有文章说这个问题。
我试了一下,如果把定义从 List<Pojo<out BasePojo>>
换成 List<Any>
后,还是往 List
里面 add Pojo<BasePojoImpl>
,序列化就是正常的,那么可以排除是 List 本身的问题。
有没有可能是对象定义的问题呢?
Pojo 定义类似如下:
Pojo<T : BasePojo>
于是我又尝试,干脆把 Pojo 的泛型去掉,序列化 List<Pojo>
,序列化也是正常的。单独序列化 Pojo<BasePojoImpl>
也是正常的,排除 Pojo 对象的问题。
唯独序列化 List<Pojo<out BasePojo>>
不行,就是闹幺蛾子。
那咋办呢,我查看了编译后的字节码,想了想 Gson 的工作机制可能是什么样,JVM 又会怎么处理。 泛型是语法糖,编译之后都是会消失的,再结合上文尝试的情况,问题应该是出在序列化泛型对象上。从常规思路来说,序列化 List 时,如果判断到类型是 List,只需要取出 List 中的元素, 对每一个元素做序列化就可以了,序列化 List<Any>
应该就是这么做的,但序列化 List<Pojo<out BasePojo>>
为什么就不这么做了呢?我也尝试过使用 fastjson,fastjson 能够正常序列化。因为时间原因,我没时间去细看 Gson 源码,但能猜到 Gson 并不是我想的这么处理的,假设 Gson 真不是这么处理的话,是不是我重写一下序列化元素 的代码让 Gson 按照我想的方式去处理就可以了?
于是我自己实现了一个 JsonSerializer
并注册到了 Gson 中。
1 | private val gson: Gson = GsonBuilder() |
然后,问题解决了。可以看到,这个 JsonSerializer
的实现我并没有做什么操作,只用了 Gson 原生的 toGsonTree 对单个元素做了转换。
由此可以得出,Gson 内部处理 List 序列化时,应该不是一个元素一个元素这么处理的。
最后
这种问题虽然对大部分的场景来说可能都不会遇到,但遇到一次也够折腾一会儿了,作为解决问题的一个小记录吧~