如何使用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
相关产品推荐
相关产品推荐

