Search code examples
javajsonjacksonjsonpathjackson2

How to make POJO and parse recursive objects using jackson?


I have a below JSON response that I am getting back from a rest service. Now I need to deserialize below JSON response into a POJO. I am working with Jackson.

{
    "pagination": {
        "number": 1,
        "entriesPerPage": 200,
        "total": 3
    },
    "postings": [{
        "categories": [{
        "taskid": "79720",
        "name": "Sunglasses",
        "parentCategory": {
            "taskid": "394",
            "name": "Sunglasses & Fashion Eyewear",
            "parentCategory": {
                "taskid": "2340",
                "name": "Men's Accessories",
                "parentCategory": {
                    "taskid": "10987",
                    "name": "Clothing, Shoes & Accessories"
                }
            }
        }
    }]
},
{
    "categories": [{
        "taskid": "12980",
        "name": "Toys",
        "parentCategory": {
            "taskid": "123",
            "name": "Fashion",
            "parentCategory": {
                "taskid": "78765",
                "name": "Men's Accessories"
            }
        }
    }]
}],
    "total": 2
}

In above json, postings is a JSON array which can have multiple posting json object. Now categories is also JSON array. Now tricky part is I can have multiple levels of parentCategory inside each category object and I don't know how many levels of parentCategory I will have. Give above JSON, I need to extract taskid of each category and taskId of last parentCategory. So it should be like this:

79720=10987
12980=78765

Where 79720 is taskId of category and 10987 is the taskId of last parentCategory. Similarly for other one.

Below is my code where I am deserializing JSON into my POJO by making an http call:

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

List<Posting> postings = response.getPostings();
for(Posting postings : postings) {
    //....
}

Confusion I have is - How to make POJO for above JSON? I tried using jsonschema2pojo but it's not making right classes for parentCategory. Since I can have nested levels of parentCategory which I don't know before hand.

Is this possible to do using Jackson?

This is the POJO class generated for Category and ParentCategory. I am not sure whether I need to make any changes here so that I can parse recursive parentCategory object.

@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 ParentCategory parentCategory;
  @JsonIgnore
  private Map<String, Object> additionalProperties = new HashMap<String, Object>();

  ...

}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class ParentCategory {
  @JsonProperty("taskid")
  private String taskid;
  @JsonProperty("name")
  private String name;
  @JsonProperty("parentCategory")
  private ParentCategory parentCategory;
  @JsonIgnore
  private Map<String, Object> additionalProperties = new HashMap<String, Object>();

  ...

}

Solution

  • This time I would approach with GSon

    Which manages recursion with less effort.

    Pojos can be made from json2pojo website, simply choosing GSon as JSon library.

    These are the Pojos:

    import java.io.Serializable;
    
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class Pagination implements Serializable
    {
    
        public Pagination() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        @SerializedName("number")
        @Expose
        private Integer number;
        @SerializedName("entriesPerPage")
        @Expose
        private Integer entriesPerPage;
        @SerializedName("total")
        @Expose
        private Integer total;
        private final static long serialVersionUID = 5114620434202813556L;
    
        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;
        }
    
    }
    
    
    
    import java.io.Serializable;
    import java.util.List;
    
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class Categories implements Serializable
    {
    
        public Categories() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        @SerializedName("pagination")
        @Expose
        private Pagination pagination;
        @SerializedName("postings")
        @Expose
        private List<Posting> postings = null;
        @SerializedName("total")
        @Expose
        private Integer total;
        private final static long serialVersionUID = 4589512697836725240L;
    
        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;
        }
    
    }
    
    
    import java.io.Serializable;
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class Category implements Serializable
    {
    
        public Category() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        @SerializedName("taskid")
        @Expose
        private String taskid;
        @SerializedName("name")
        @Expose
        private String name;
        @SerializedName("parentCategory")
        @Expose
        private ParentCategory parentCategory;
        private final static long serialVersionUID = -2127963072268572959L;
    
        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 ParentCategory getParentCategory() {
            return parentCategory;
        }
    
        public void setParentCategory(ParentCategory parentCategory) {
            this.parentCategory = parentCategory;
        }
    
    }
    
    
    import java.io.Serializable;
    import java.util.List;
    
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class Posting implements Serializable
    {
    
        @SerializedName("categories")
        @Expose
        private List<Category> categories = null;
        private final static long serialVersionUID = 8135185675909461065L;
    
        public List<Category> getCategories() {
            return categories;
        }
    
        public Posting() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        public void setCategories(List<Category> categories) {
            this.categories = categories;
        }
    
    }
    
    
    import java.io.Serializable;
    import java.util.List;
    
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class ParentCategory implements Serializable
    {
    
        @SerializedName("taskid")
        @Expose
        private String taskid;
        @SerializedName("name")
        @Expose
        private String name;
        @SerializedName("parentCategory")
        @Expose
        private List<ParentCategory>  parentCategory;
    
    
        public ParentCategory() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        private final static long serialVersionUID = -5989749742502713615L;
    
        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 List<ParentCategory> getParentCategory() {
            return parentCategory;
        }
    
        public void setParentCategory(List<ParentCategory> parentCategory) {
            this.parentCategory = parentCategory;
        }
    
    }
    

    So this is a test implementation:

     Pagination pagination = new Pagination();
    
             pagination.setNumber(1);
             pagination.setEntriesPerPage(200);
             pagination.setTotal(3);
    
             Categories categories = new Categories(); 
             categories.setPagination(pagination);
    
             Category category = new Category();
             category.setName("Sunglasses");
             category.setTaskid("79720");
    
             List<Category> categoryList = new ArrayList<Category>();
    
             Posting posting = new Posting(); 
             posting.setCategories(categoryList);
    
             List<ParentCategory> parentCategoryList = new ArrayList<ParentCategory>();
             List<ParentCategory> parentCategoryList2 = new ArrayList<ParentCategory>();
    
             ParentCategory  parentCategory1 = new ParentCategory(); 
             parentCategory1.setName("Sunglasses & Fashion Eyewear");
             parentCategory1.setTaskid("394");
    
             ParentCategory  parentCategory2 = new ParentCategory(); 
             parentCategory2.setName("Men's Accessories");
             parentCategory2.setTaskid("2340");
    
             ParentCategory  parentCategory3 = new ParentCategory(); 
             parentCategory3.setName("Clothing, Shoes & Accessories");
             parentCategory3.setTaskid("10987");
    
             parentCategoryList.add(parentCategory2); 
             parentCategoryList2.add(parentCategory3);
              parentCategory2.setParentCategory(parentCategoryList2);
             parentCategory1.setParentCategory(parentCategoryList);
             category.setParentCategory(parentCategory1);
    
              Gson gson = new Gson();
                System.out.println(gson.toJson(category));
    

    ...and this is the resulting Json:

    {
        "taskid": "79720",
        "name": "Sunglasses",
        "parentCategory": {
            "taskid": "394",
            "name": "Sunglasses \u0026 Fashion Eyewear",
            "parentCategory": [{
                "taskid": "2340",
                "name": "Men\u0027s Accessories",
                "parentCategory": [{
                    "taskid": "10987",
                    "name": "Clothing, Shoes \u0026 Accessories"
                }]
            }]
        }
    }
    

    Maybe still need a bit of tweaking but you got the idea.

    Hope it helps!

    EDIT: as the op requests I add the Jackson Version.

    Pojos:

    import java.io.Serializable;
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonPropertyOrder({"taskid", "name", "parentCategory"})
    public class ParentCategory implements Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        @JsonProperty("taskid")
        private String taskid;
        @JsonProperty("name")
        private String name;
        @JsonProperty("parentCategory")
        private ParentCategory parentCategory;
        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 ParentCategory getParentCategory() {
            return parentCategory;
        }
        public void setParentCategory(ParentCategory parentCategory) {
            this.parentCategory = parentCategory;
        }
    
    
    }
    
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonPropertyOrder({"taskid", "name", "parentCategory"})
    public class Category implements Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        @JsonProperty("taskid")
        private String taskid;
        @JsonProperty("name")
        private String name;
        @JsonProperty("parentCategory")
        private ParentCategory parentCategory;
    
        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 ParentCategory getParentCategory() {
            return parentCategory;
        }
        public void setParentCategory(ParentCategory parentCategory) {
            this.parentCategory = parentCategory;
        }
    
    
    
    }
    
    
    public class Test {
    
    
        public static void main(String[] args) throws JsonProcessingException {
    
    
             Category category = new Category();
             category.setName("Sunglasses");
             category.setTaskid("79720");
    
             List<Category> categoryList = new ArrayList<Category>();
    
             List<ParentCategory> parentCategoryList = new ArrayList<ParentCategory>();
             List<ParentCategory> parentCategoryList2 = new ArrayList<ParentCategory>();
    
             ParentCategory  parentCategory1 = new ParentCategory(); 
             parentCategory1.setName("Sunglasses & Fashion Eyewear");
             parentCategory1.setTaskid("394");
    
             ParentCategory  parentCategory2 = new ParentCategory(); 
             parentCategory2.setName("Men's Accessories");
             parentCategory2.setTaskid("2340");
    
             ParentCategory  parentCategory3 = new ParentCategory(); 
             parentCategory3.setName("Clothing, Shoes & Accessories");
             parentCategory3.setTaskid("10987");
    
             parentCategory1.setParentCategory(parentCategory2);
             parentCategory2.setParentCategory(parentCategory3);
             category.setParentCategory(parentCategory1);
    
            ObjectMapper objectMapper = new ObjectMapper();
    
            String testJson = objectMapper.writeValueAsString(category);
            System.out.println(testJson);
        }
    
    }
    

    And here again a test result:

    {
        "taskid": "79720",
        "name": "Sunglasses",
        "parentCategory": {
            "taskid": "394",
            "name": "Sunglasses & Fashion Eyewear",
            "parentCategory": {
                "taskid": "2340",
                "name": "Men's Accessories",
                "parentCategory": {
                    "taskid": "10987",
                    "name": "Clothing, Shoes & Accessories"
                }
            }
        }
    }