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

Jackson继承反序列化引发无限循环的解决方案咨询

解决Jackson自定义反序列化器无限循环与冗余类问题

核心问题

无法通过@JsonSubTypes处理给定格式的JSON,自定义AnimalDeserializer中return codec.treeToValue(node, Animal.class)语句触发无限循环;当前通过将Animal设为抽象类并新增DefaultAnimal类规避,但会产生冗余类,需更优方案。

给定JSON(不可修改):

[
  {
    "name": "dog name",
    "type": "dog",
    "age": 5
  },
  {
    "name": "cat name",
    "type": "cat",
    "color": "black"
  }
]

修正后基础类定义(移除Dog类重复的name字段):

class Animal {
  String name;
}

class Dog extends Animal {
    int age;
}

优化方案一:手动构建Animal实例,避免递归调用

直接解析JsonNode手动创建并填充Animal对象,不调用codec.treeToValue触发自定义反序列化器,从根源避免循环。

修改后的AnimalDeserializer:

public class AnimalDeserializer extends StdDeserializer<Animal> {
  public AnimalDeserializer() {
    super(Animal.class);
  }

  @Override
  public Animal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
    ObjectCodec codec = p.getCodec();
    JsonNode node = codec.readTree(p);

    JsonNode typeNode = node.get("type");
    if (typeNode != null && !typeNode.isNull()) {
      String typeText = typeNode.asText();
      if ("dog".equals(typeText)) {
        return codec.treeToValue(node, Dog.class);
      }
      // 可扩展其他类型,比如Cat
    }

    // 手动构建Animal实例,不触发自定义反序列化器
    Animal animal = new Animal();
    if (node.has("name")) {
      animal.name = node.get("name").asText();
    }
    return animal;
  }
}

在Animal类绑定反序列化器:

@JsonDeserialize(using = AnimalDeserializer.class)
class Animal {
  String name;
}

优化方案二:使用默认BeanDeserializer绕过自定义逻辑

从DeserializationContext获取Jackson默认的BeanDeserializer处理Animal类,绕过自定义反序列化器,避免循环调用。

修改后的AnimalDeserializer:

public class AnimalDeserializer extends StdDeserializer<Animal> {
  private final BeanDeserializer defaultDeserializer;

  public AnimalDeserializer(BeanDeserializer defaultDeserializer) {
    super(Animal.class);
    this.defaultDeserializer = defaultDeserializer;
  }

  @Override
  public Animal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
    ObjectCodec codec = p.getCodec();
    JsonNode node = codec.readTree(p);

    JsonNode typeNode = node.get("type");
    if (typeNode != null && !typeNode.isNull()) {
      String typeText = typeNode.asText();
      if ("dog".equals(typeText)) {
        // 将JsonNode转回JsonParser,避免位置异常
        JsonParser nodeParser = node.traverse(codec);
        nodeParser.nextToken();
        return ctxt.readValue(nodeParser, Dog.class);
      }
    }

    // 使用默认反序列化器处理Animal,不触发自定义逻辑
    JsonParser nodeParser = node.traverse(codec);
    nodeParser.nextToken();
    return defaultDeserializer.deserialize(nodeParser, ctxt);
  }
}

通过SimpleModule注册时传入默认反序列化器:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
// 获取Animal的默认BeanDeserializer
BeanDeserializer defaultDeserializer = (BeanDeserializer) mapper.getDeserializationConfig()
    .getDeserializerProvider()
    .findValueDeserializer(mapper.constructType(Animal.class));
module.addDeserializer(Animal.class, new AnimalDeserializer(defaultDeserializer));
mapper.registerModule(module);

优化方案三:修复@JsonSubTypes配置(优先推荐)

若之前@JsonSubTypes配置错误,可通过正确配置实现自动反序列化,无需自定义反序列化器。

修改Animal类:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type" // 指定JSON中的类型字段
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    // 可添加其他类型,比如Cat.class对应"cat"
})
class Animal {
  String name;
}

直接用ObjectMapper反序列化:

List<Animal> animals = mapper.readValue(jsonString, new TypeReference<List<Animal>>() {});

内容的提问来源于stack exchange,提问作者evol1102

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:30:08