Spring Boot3.2+Java21升级后Jackson自定义类型解析序列化报错
Spring Boot 3.2 + Java 21 + Jackson 2.15.3 序列化异常排查思路
问题背景
升级Spring Boot至3.2、Java至21,同步更新Jackson到2.15.3后,实现接口且配置JsonTypeIdResolver的类出现序列化异常。执行ObjectMapperService.objectMapperForFilters.writeValueAsString(Screen1Filter(...))时抛出:
com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value
未配置JsonTypeIdResolver的对象序列化正常。
相关代码
接口定义
@JsonTypeInfo( use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "screen", visible = true ) @JsonTypeIdResolver(BaseFilterResolver::class) interface BaseFilter: ProjectFilter { val id: Long? val screen: Screen }
实现类
data class Screen1Filter( override val id: Long? = null, val period: Period?, //... other properties override val screen: Screen = Screen.SCREEN1 ): BaseFilter {...}
自定义类型ID解析器
class BaseFilterResolver : TypeIdResolverBase() { private var superType: JavaType? = null override fun init(baseType: JavaType?) { superType = baseType } override fun idFromValue(obj: Any): String? { return null } override fun idFromValueAndType(obj: Any?, subType: Class<*>): String? { return null } override fun typeFromId(context: DatabindContext, id: String?): JavaType { return context.constructSpecializedType(superType, Screen.values().find { it.name == id }!!.filterClass) } override fun getMechanism(): JsonTypeInfo.Id { return JsonTypeInfo.Id.CUSTOM; } }
解决思路
- 修复ID生成逻辑:你的
BaseFilterResolver中idFromValue和idFromValueAndType方法都返回null,Jackson序列化时依赖这两个方法获取类型标识,返回null会打乱序列化流程,触发字段写入顺序错误。修改这两个方法,从对象中提取screen字段的名称作为ID:override fun idFromValue(obj: Any): String? { return (obj as BaseFilter).screen.name } override fun idFromValueAndType(obj: Any?, subType: Class<*>): String? { return obj?.let { (it as BaseFilter).screen.name } ?: Screen.values().find { it.filterClass == subType }?.name } - 匹配配置与Resolver逻辑:Jackson 2.15.x对自定义类型解析器的校验更严格,你使用
include = As.EXISTING_PROPERTY意味着复用已有screen字段作为类型标识,Resolver必须正确返回该字段对应的序列化值,不能返回null。 - 验证枚举映射一致性:确认
Screen枚举的name属性和screen字段序列化后的输出值完全匹配,避免反序列化时类型匹配失败。 - 开启调试日志:将
com.fasterxml.jackson.databind日志级别设为DEBUG,观察类型ID的生成和写入过程,确认Resolver输出符合预期。
内容的提问来源于stack exchange,提问作者Evgeni Dimitrov
相关产品推荐
相关产品推荐

