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

使用@JsonTypeInfo反序列化含额外字段的混合类型JSON数组报错

解决Jackson混合类型数组解析时同级字段映射异常问题

问题根源

你当前的Java模型使用@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT),Jackson会认为每个OperationElement实例必须完全被extension或core节点包裹(即整个对象是{"extension": {...}}或{"core": {...}})。但你的JSON结构中,name、tags是和extension/core同级的顶层字段,超出了Jackson预期的包裹范围,导致无法映射这些字段,抛出MismatchedInputException。

最优解决方案:调整模型结构匹配JSON层级

直接修改Java模型,让它完全对应JSON的层级结构:创建一个Operation类来承载同级的name、tags字段,再用一个抽象类OperationContent来处理extension/core的混合类型。

修改后的完整代码:

@Data
public class Payload {

  private List<Operation> operations;

  @Data
  public static class Operation {
    // 直接映射JSON中的同级字段
    private String name;
    private String tags;

    // 用WRAPPER_OBJECT识别混合类型的content字段
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
    @JsonSubTypes({
      @JsonSubTypes.Type(value = Extension.class, name = "extension"),
      @JsonSubTypes.Type(value = Core.class, name = "core")
    })
    private OperationContent content;
  }

  // 抽象父类定义混合类型的公共标识
  @Data
  public static abstract class OperationContent {}

  // Extension类型对应JSON中的extension节点
  @Data
  public static class Extension extends OperationContent {
    private String serviceType;
    private String serviceId;
  }

  // Core类型对应JSON中的core节点
  @Data
  public static class Core extends OperationContent {
    private Config config;
    private String displayName;

    @Data
    public static class Config {
      private Long a;
      private Long b;
    }
  }

  public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    Payload operationsPayload = mapper.readValue(
      Files.readAllBytes(Paths.get("C:\\desc", "file.json")), Payload.class);
    System.out.println(operationsPayload);
  }
}

方案说明

  1. 层级对应:Operation类完全匹配JSON中每个operations元素的结构,name、tags直接映射同级字段,content字段对应extension/core节点。
  2. 类型识别:通过@JsonTypeInfo(include = WRAPPER_OBJECT),Jackson会自动识别extension或core节点,并将其解析为对应的Extension或Core实例,赋值给content字段。
  3. 无额外配置:不需要自定义解析器或复杂注解,完全利用Jackson原生注解实现,代码简洁易维护。

备选方案:自定义反序列化器(保留原模型结构)

如果无法修改模型结构,可以通过自定义反序列化器手动处理字段映射:

步骤1:自定义反序列化器

public static class OperationElementDeserializer extends StdDeserializer<OperationElement> {
  protected OperationElementDeserializer() {
    super(OperationElement.class);
  }

  @Override
  public OperationElement deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
    JsonNode node = p.readValueAsTree();
    ObjectMapper mapper = (ObjectMapper) p.getCodec();
    OperationElement element;

    // 根据存在的节点判断类型
    if (node.has("extension")) {
      element = mapper.treeToValue(node, Extension.class);
    } else if (node.has("core")) {
      element = mapper.treeToValue(node, Core.class);
    } else {
      throw new IllegalArgumentException("未知的操作类型");
    }

    // 手动设置父类的name和tags字段
    element.setName(node.get("name").asText());
    element.setTags(node.get("tags").asText());
    return element;
  }
}

步骤2:修改抽象类注解

在OperationElement上添加自定义反序列化器注解:

@Data
@JsonDeserialize(using = OperationElementDeserializer.class)
public static abstract class OperationElement {
  private String name;
  private String tags;
}

步骤3:移除原类型注解

删除OperationElement上的@JsonTypeInfo和@JsonSubTypes注解,以及子类的@JsonRootName注解,让自定义反序列化器接管类型判断和字段映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:54:32