You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 (token JsonToken.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 23:27:27