Kotlin原生序列化如何避免使用不符合实际的@SerialName注解?
报错根本原因
你出现类转换异常的核心问题是自定义序列化器的泛型目标和挂载的类不匹配:
- 之前把序列化器挂在
vehicles字段上时,序列化器的设计目标是产出List<Vehicle>类型的值,所以继承的基类是JsonTransformingSerializer<List<Vehicle>>,框架会把序列化器返回的列表直接赋值给vehicles字段,整个过程逻辑是自洽的。 - 你把序列化器移到类层级挂载后,没有同步调整序列化器的泛型定义,序列化器实际还是按“返回List”的逻辑运行,但框架要求这个序列化器必须产出
VehicleResponse类型的实例。框架拿到序列化器返回的ArrayList后,强行做类型强转,就触发了ArrayList cannot be cast to VehicleResponse的报错。
简单来说:你改了序列化器的挂载位置,却沿用了原来针对列表的序列化器逻辑,相当于拿处理列表的工具去处理整个类的实例,自然会出现类型不匹配的问题。
正确实现方案
1. 调整序列化器的泛型目标
因为现在序列化器要直接产出VehicleResponse实例,不能再沿用针对List<Vehicle>的转换逻辑,需要把基类的泛型改成VehicleResponse,把类本身的序列化器作为基类参数传入。
注意:给类手动挂载自定义序列化器后,不要额外加自动生成的
@Serializable注解,否则会出现重复注册序列化器的冲突问题。
2. 适配转换逻辑的输出结构
你之前写的从根JSON逐层遍历到data.children数组的逻辑是正确的,只需要在提取完所有车辆数据节点后,把结果封装成匹配VehicleResponse结构的JSON对象即可——不能再直接返回提取好的车辆数组,否则还是会出现类型不匹配。
完整的可运行代码示例:
// 在类层级指定自定义序列化器,不再依赖字段上的假注解 @Serializable(with = VehicleResponseSerializer::class) data class VehicleResponse( val vehicles: List<Vehicle> ) @Serializable data class Vehicle(val id: Int) // 泛型明确指定为VehicleResponse,和挂载的目标类型完全一致 object VehicleResponseSerializer : JsonTransformingSerializer<VehicleResponse>(VehicleResponse.serializer()) { override fun transformDeserialize(element: JsonElement): JsonElement { // 直接从传入的根JSON对象开始逐层定位,不需要框架提前帮你截取节点 val childrenArray = element.jsonObject["data"]!!.jsonObject["children"]!!.jsonArray // 提取每个子项内部的data节点,也就是我们真正需要的车辆数据 val vehicleDataList = childrenArray.map { item -> item.jsonObject["data"]!! } // 把提取的车辆列表封装成和VehicleResponse结构匹配的JSON对象 return buildJsonObject { put("vehicles", JsonArray(vehicleDataList)) } } }
3. 效果验证
按照上面的修改,配置好ignoreUnknownKeys = true后,反序列化逻辑可以直接正常解析示例中的JSON,最终得到的结果和原实现完全一致:
- 不需要在
vehicles字段上加不符合真实结构的@SerialName("data")注解 - 业务侧的数据类定义和实际需要的结构完全一致,不会给后续维护造成误解
- 所有嵌套路径的遍历、无用数据的过滤逻辑全部收敛在序列化器内部,代码可读性更强
内容的提问来源于stack exchange,提问作者cris
相关产品推荐
相关产品推荐

