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

Jackson递归结构序列化问题:仅输出qNodeId,子节点丢失

Jackson递归结构序列化/反序列化问题修复

我定义了Node、CNode、QNode三种核心节点类型:QNode继承自最基础的Node类,包含额外字段,且可拥有CNode列表(CNode可引用其他CNode,但不会引用父QNode);QNode中可选包含TypeInfo类实例,而TypeInfo可拥有可选的Node引用。在使用Jackson将该递归结构序列化/反序列化为JSON与Java对象时,仅能获取QNode的qNodeId及其额外属性,子节点对象无法正常输出。

示例JSON输入

{
  "qNodes": [
    {
        "qNodeId": "Q-11122",
        "id": "PO11111",
        "typeInfo": {
          "applicationLevel": "medium",
          "required": true
         },
        "cNodes": [
          {
              "cNodeId": "Q-11155",
              "cNodes": [
                {
                  "qNodeId": "Q-7420",
                  "typeInfo": {
                    "applicationLevel": "low",
                    "assetNode": {
                      "id": "WQ-222",
                      "qNode": {
                        "qNodeId": "Q-0988"
                      }
                    },
                    "required": true
                  },
                  "url": "https://example.com ",
                  "id": "qS111"
                }
              ]
          }
        ]
      }
  ]
}

问题分析

导致子节点无法正常反序列化的核心原因如下:

  • 构造函数的@JsonCreator参数与JSON字段不匹配,Jackson无法正确初始化对象
  • 部分关键字段缺少@JsonProperty注解,无法建立JSON与Java字段的映射
  • 部分类缺少Lombok的@Data注解,没有生成getter/setter,Jackson无法访问字段
  • CNode类缺少子CNode列表字段,与JSON结构不匹配

修复后的代码实现

BaseNode类

修正@JsonAnySetter方法名,确保Jackson正确识别额外属性:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.HashMap;
import java.util.Map;

@Data
@NoArgsConstructor
public class BaseNode {
    protected String id;
    protected Map<String, String> additionalProperties = new HashMap<>();

    @JsonCreator
    public BaseNode(@JsonProperty("id") String id) {
        this.id = id;
    }

    @JsonAnySetter
    public void setAdditionalProperties(String property, String value) {
        this.additionalProperties.put(property, value);
    }
}

Node类

简化构造函数,添加@JsonProperty确保字段映射:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class Node {
    @JsonProperty("id")
    private String id;
    @JsonProperty("qNode")
    private QNode qNode;

    @JsonCreator
    public Node(@JsonProperty("id") String id, @JsonProperty("qNode") QNode qNode) {
        this.id = id;
        this.qNode = qNode;
    }
}

TypeInfo类

添加@Data和@JsonProperty注解,修正枚举与JSON字符串的映射:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class TypeInfo {
    public enum Level {
        low, medium, high;
    }

    @JsonProperty("applicationLevel")
    private Level applicationLevel;
    @JsonProperty("assetNode")
    private Node assetNode;
    @JsonProperty("required")
    private boolean required;
}

CNode类

添加子CNode列表字段,修正构造函数,添加必要注解:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CNode {
    @JsonProperty("cNodeId")
    private String cNodeId;
    @JsonProperty("qNode")
    private QNode qNode;
    @JsonProperty("cNodes")
    private List<CNode> cNodes;

    @JsonCreator
    public CNode(@JsonProperty("cNodeId") String cNodeId,
                 @JsonProperty("qNode") QNode qNode,
                 @JsonProperty("cNodes") List<CNode> cNodes) {
        this.cNodeId = cNodeId;
        this.qNode = qNode;
        this.cNodes = cNodes;
    }
}

QNode类

修正构造函数参数,为typeInfo添加@JsonProperty,修正@JsonAnySetter方法:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
public class QNode extends BaseNode {
    @JsonProperty("qNodeId")
    private String qNodeId;
    @JsonProperty("cNodes")
    private List<CNode> cNodes;
    @JsonProperty("typeInfo")
    private TypeInfo typeInfo;
    private Map<String, String> additionalElements = new HashMap<>();

    @JsonCreator
    public QNode(@JsonProperty("id") String id,
                 @JsonProperty("qNodeId") String qNodeId,
                 @JsonProperty("cNodes") List<CNode> cNodes,
                 @JsonProperty("typeInfo") TypeInfo typeInfo) {
        super(id);
        this.qNodeId = qNodeId;
        this.cNodes = cNodes;
        this.typeInfo = typeInfo;
    }

    @JsonAnySetter
    public void setAdditionalElements(String property, String value) {
        this.additionalElements.put(property, value);
    }
}

QNodeContainer类

保持原结构即可:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
public class QNodeContainer {
    @JsonProperty("qNodes")
    private List<QNode> qNodes;

    @JsonCreator
    public QNodeContainer(@JsonProperty("qNodes") List<QNode> qNodes) {
        this.qNodes = qNodes;
    }
}

反序列化代码

确保ObjectMapper配置正确,验证反序列化结果:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.nio.file.Files;

public class DeserializeDemo {
    public static void main(String[] args) throws Exception {
        File resource2 = new ClassPathResource("data.json").getFile();
        String dataJson = new String(Files.readAllBytes(resource2.toPath()));
        
        ObjectMapper mapper = new ObjectMapper()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        
        QNodeContainer qNodes = mapper.readValue(dataJson, QNodeContainer.class);
        // 验证反序列化结果
        System.out.println(qNodes.getQNodes().get(0).getTypeInfo().getApplicationLevel());
        System.out.println(qNodes.getQNodes().get(0).getCNodes().get(0).getCNodes().get(0).getQNodeId());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:55:32