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

如何使用Jackson创建POJO并解析含递归parentCategory的JSON?

当然可以用Jackson实现你的需求!

问题出在自动生成的POJO把Category和ParentCategory拆成了两个类——但实际上这两个结构完全一致,只是存在递归引用关系。只需要把它们合并成一个类,让它递归引用自己,就能轻松解决反序列化的问题,再配合一个工具方法提取最底层父分类的taskid即可。

第一步:修改POJO类

1. Category类(核心:递归引用自身)

这个类同时表示分类和它的父分类,字段parentCategory的类型就是Category本身,Jackson会自动处理这种递归结构:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class Category {
    @JsonProperty("taskid")
    private String taskid;
    @JsonProperty("name")
    private String name;
    @JsonProperty("parentCategory")
    private Category parentCategory; // 递归引用自身
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<>();

    // 自动生成Getter和Setter
    public String getTaskid() { return taskid; }
    public void setTaskid(String taskid) { this.taskid = taskid; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Category getParentCategory() { return parentCategory; }
    public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; }
    public Map<String, Object> getAdditionalProperties() { return additionalProperties; }
    public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }

    // 工具方法:获取最底层父分类的taskid(用循环避免深层递归栈溢出)
    public String getRootParentTaskId() {
        Category currentParent = this.parentCategory;
        // 一直找到没有父分类的节点
        while (currentParent != null && currentParent.getParentCategory() != null) {
            currentParent = currentParent.getParentCategory();
        }
        return currentParent != null ? currentParent.getTaskid() : null;
    }
}

2. Posting类

结构保持简单,对应JSON中的postings数组元素:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"categories"})
public class Posting {
    @JsonProperty("categories")
    private List<Category> categories;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<>();

    // Getter和Setter
    public List<Category> getCategories() { return categories; }
    public void setCategories(List<Category> categories) { this.categories = categories; }
    public Map<String, Object> getAdditionalProperties() { return additionalProperties; }
    public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
}

3. Stuff类(顶层响应类)

对应整个JSON响应结构:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"pagination", "postings", "total"})
public class Stuff {
    @JsonProperty("pagination")
    private Pagination pagination;
    @JsonProperty("postings")
    private List<Posting> postings;
    @JsonProperty("total")
    private Integer total;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<>();

    // Getter和Setter
    public Pagination getPagination() { return pagination; }
    public void setPagination(Pagination pagination) { this.pagination = pagination; }
    public List<Posting> getPostings() { return postings; }
    public void setPostings(List<Posting> postings) { this.postings = postings; }
    public Integer getTotal() { return total; }
    public void setTotal(Integer total) { this.total = total; }
    public Map<String, Object> getAdditionalProperties() { return additionalProperties; }
    public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
}

4. Pagination类(可选,根据需要保留)

对应JSON中的pagination字段:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"number", "entriesPerPage", "total"})
public class Pagination {
    @JsonProperty("number")
    private Integer number;
    @JsonProperty("entriesPerPage")
    private Integer entriesPerPage;
    @JsonProperty("total")
    private Integer total;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<>();

    // Getter和Setter
    public Integer getNumber() { return number; }
    public void setNumber(Integer number) { this.number = number; }
    public Integer getEntriesPerPage() { return entriesPerPage; }
    public void setEntriesPerPage(Integer entriesPerPage) { this.entriesPerPage = entriesPerPage; }
    public Integer getTotal() { return total; }
    public void setTotal(Integer total) { this.total = total; }
    public Map<String, Object> getAdditionalProperties() { return additionalProperties; }
    public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
}

第二步:处理响应并提取目标数据

在你的原有代码基础上,遍历postings和categories,调用getRootParentTaskId()方法即可得到需要的格式:

ResponseEntity<Stuff> responseEntity = HttpClient.getInstance().getClient()
        .exchange(URI.create(endpoint), HttpMethod.POST, requestEntity, Stuff.class);
Stuff response = responseEntity.getBody();

if (response != null && response.getPostings() != null) {
    for (Posting posting : response.getPostings()) {
        if (posting.getCategories() != null) {
            for (Category category : posting.getCategories()) {
                String currentTaskId = category.getTaskid();
                String rootParentTaskId = category.getRootParentTaskId();
                // 确保两个ID都不为空再输出
                if (currentTaskId != null && rootParentTaskId != null) {
                    String result = String.format("%s=%s", currentTaskId, rootParentTaskId);
                    System.out.println(result); // 或者收集到集合中后续使用
                }
            }
        }
    }
}

为什么原来的POJO不行?

自动生成的ParentCategory类虽然也做了递归,但Jackson在反序列化时,当遇到parentCategory嵌套的情况,会尝试将其映射到ParentCategory类型,而不是Category——但两者结构完全一致,拆分反而造成了类型匹配问题。合并成一个类后,递归引用自身,Jackson就能正确识别并反序列化任意层级的父分类了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:46:27