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

如何使用Jackson反序列化以带@JsonIdentityInfo的MyType为键的Map?

如何反序列化以MyType的id为键的Map JSON?

给定如下代码:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class MyType {

   String id;
   ... // id的getter和setter

   String longText;
}

public class MyData {

   List<MyType> types;

   @JsonIdentityReference(alwaysAsId = true) // 仅序列化有效
   Map<MyType, Integer> countMap;
}

该代码可以将MyData正确序列化为以下JSON:

{
  "types": [
    {
      "id": "123",
      "longText": "very long text 1 ..."
    },
    {
      "id": "456",
      "longText": "very long text 2 ..."
    }
  ],
  "countMap": {
    "123": 100,
    "456": 200
  }
}

但反序列化时会抛出错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot find a (Map) Key deserializer for type [simple type, class MyType]

解决方法

问题根源在于@JsonIdentityReference(alwaysAsId = true)仅处理序列化逻辑,将MyType对象替换为id字符串;但反序列化时,Jackson不知道如何把字符串键转换为MyType实例,因此需要自定义键反序列化器。

方法1:自定义KeyDeserializer并绑定到字段

  1. 实现KeyDeserializer,定义字符串id到MyType的转换逻辑:
public class MyTypeKeyDeserializer extends KeyDeserializer {
    @Override
    public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
        // 基础逻辑:直接通过id创建MyType实例
        MyType myType = new MyType();
        myType.setId(key);
        
        // 进阶逻辑:如果需要复用types列表中的已有实例(避免创建新对象)
        // 可以通过上下文获取当前正在反序列化的MyData对象,从types中匹配id
        // MyData myData = (MyData) ctxt.getParser().getParsingContext().getParent().getCurrentValue();
        // for (MyType type : myData.getTypes()) {
        //     if (key.equals(type.getId())) {
        //         return type;
        //     }
        // }
        
        return myType;
    }
}
  1. 在countMap字段上添加@JsonKeyDeserialize注解,指定使用自定义的反序列化器:
public class MyData {
    List<MyType> types;

    @JsonIdentityReference(alwaysAsId = true)
    @JsonKeyDeserialize(using = MyTypeKeyDeserializer.class)
    Map<MyType, Integer> countMap;
}

方法2:全局注册KeyDeserializer

如果多个地方都需要处理MyType作为Map键的反序列化,可以在ObjectMapper中全局注册:

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addKeyDeserializer(MyType.class, new MyTypeKeyDeserializer());
objectMapper.registerModule(module);

这样无需在每个字段上添加注解,全局生效。

内容的提问来源于stack exchange,提问作者Geoffrey De Smet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:58:19