Jackson序列化EmptyTagHolder后无法反序列化的解决方案咨询
问题:Jackson反序列化EmptyTagHolder时的数组类型不匹配异常
我在序列化一个包含大量多态嵌套属性的编辑器状态对象(存入Redis缓存以避免高成本数据库查询)时,遇到EmptyTagHolder空占位符对象的反序列化异常。
相关代码定义
EmptyTagHolder实现类
class EmptyTagHolder<T> : TagHolder<T> { override fun contains(tag: T) = false override fun plus(other: TagHolder<T>) = other override fun plus(other: T) = TagSet(other) override fun iterator() = emptyList<T>().iterator() }
TagHolder接口
interface TagHolder<TagType> : Iterable<TagType> { operator fun contains(tag: TagType): Boolean operator fun plus(other: TagHolder<TagType>): TagHolder<TagType> operator fun plus(other: TagType): TagHolder<TagType> }
Entity接口与LocalEntity实现类
interface Entity { val id: SourceAwareIdentifier val type: EntityType val tags: TagHolder<EntityTag> val adjacencyTags: TagHolder<EntityTag> val properties: PropertyStore }
data class LocalEntity( override val id: SourceAwareIdentifier, override val type: EntityType, override val tags: TagHolder<EntityTag>, override val adjacencyTags: TagHolder<EntityTag>, override val properties: EditablePropertyStore, ) : Entity
序列化与反序列化问题
Jackson将EmptyTagHolder实例序列化为如下结构:
{ "[package].EmptyTagHolder": [ ] }
但反序列化时抛出异常:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type
[package].EmptyTagHolder<[package].EntityTag>from Array value (tokenJsonToken.START_ARRAY)
完整序列化后的JSON示例:
{ "entity": { "somepackage.data.network.local.model.entity.LocalEntity": { "label": "Test", "id": { "somepackage.data.network.model.id.impl.RawSourceAwareIdentifier": { "source": "local", "internalId": "local:57fc8745-706e-4159-847f-7a35182d330f" } }, "type": { "somepackage.data.network.model.entity.EntityType": "Regular" }, "tags": { "somepackage.data.generic.impl.TagSet": { "tags": { "java.util.Collections$SingletonSet": [ { "somepackage.data.network.model.entity.EntityTag": "Lorem" } ] } } }, "adjacencyTags": { "somepackage.data.generic.impl.EmptyTagHolder": [ ] }, "properties": { "somepackage.data.generic.propertystore.impl.BasicEditablePropertyStore": { "overlay": { "somepackage.data.generic.propertystore.impl.NoopEditablePropertyStoreOverlay": { } } } } } } }
解决方案
1. 为EmptyTagHolder添加自定义反序列化器
EmptyTagHolder无状态属性,Jackson序列化时生成的数组结构无法直接映射到实例,自定义反序列化器忽略输入内容直接返回实例:
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.JsonNode class EmptyTagHolderDeserializer<T> : JsonDeserializer<EmptyTagHolder<T>>() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext): EmptyTagHolder<T> { p.codec.readTree(p) // 读取并忽略输入的数组节点 return EmptyTagHolder() } }
为EmptyTagHolder类添加反序列化注解:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize @JsonDeserialize(using = EmptyTagHolderDeserializer::class) class EmptyTagHolder<T> : TagHolder<T> { // 原有实现代码 }
2. 统一配置Jackson多态类型处理(可选)
若项目存在大量多态接口序列化需求,可通过ObjectMapper统一配置多态类型处理规则,提升一致性:
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator import com.fasterxml.jackson.module.kotlin.registerKotlinModule val objectMapper = ObjectMapper().apply { registerKotlinModule() // 启用默认多态类型处理,对非final类型自动添加类型标识 activateDefaultTyping( LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL ) }
3. 优化EmptyTagHolder序列化输出(可选)
若希望EmptyTagHolder的序列化结构更简洁,可添加自定义序列化器,将其序列化为空对象(或null),需配合反序列化器使用:
import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.JsonSerializer import com.fasterxml.jackson.databind.SerializerProvider class EmptyTagHolderSerializer<T> : JsonSerializer<EmptyTagHolder<T>>() { override fun serialize(value: EmptyTagHolder<T>?, gen: JsonGenerator, serializers: SerializerProvider) { gen.writeStartObject() gen.writeEndObject() } }
同时为类添加序列化与反序列化注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.databind.annotation.JsonDeserialize @JsonSerialize(using = EmptyTagHolderSerializer::class) @JsonDeserialize(using = EmptyTagHolderDeserializer::class) class EmptyTagHolder<T> : TagHolder<T> { // 原有实现代码 }
内容的提问来源于stack exchange,提问作者k.meinkopf
相关产品推荐
相关产品推荐

