Search code examples
javajsontreehierarchyraw-data

Create Json Hierarchy from from raw data of parent child id


Data columns look like :

CompanyId,Parent Id
1,1
2,1
3,1
4,2
5,2

each company belongs to some parent. My need to is convert this raw data into below json format.

[
 {
   id : 1 
   child : [
            {
                id : 2
                child : [
                          {
                           id : 4
                          },
                          {
                           id : 5
                          }
                        ]
            },
            {
                id : 3
            }
           ]
  }
]

any java code implementation will be helpful.


Solution

  • Assuming the data table looks like this:

    Map<Integer, Integer> childToParent = new HashMap<>();
    childToParent.put(1, 1);
    childToParent.put(2, 1);
    childToParent.put(3, 1);
    childToParent.put(4, 2);
    childToParent.put(5, 2);
    

    We can create a parent to children map:

    Map<Integer, List<Integer>> parentToChildren = childToParent.entrySet().stream()
            .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
    

    For simplicity, let's create a Company class likewise:

    @Data
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class Company {
        private final int id;
        @JsonProperty(value = "child")
        private List<Company> children;
    }
    

    Then create Company objects:

    Map<Integer, Company> idToCompany = childToParent.keySet().stream()
            .map(integer -> new Company(integer,  null))
            .collect(Collectors.toMap(Company::getId, company -> company));
    

    And now we can set the children for each parent:

    idToCompany.values().forEach(company -> {
        List<Integer> childrenIds = parentToChildren.get(company.getId());
    
        if(childrenIds != null){
            List<Company> children = childrenIds.stream()
                    .filter(childId -> childId != company.getId()) // a company can't be a parent of itself
                    .map(idToCompany::get)
                    .collect(Collectors.toList());
            company.setChildren(children);
        }
    });
    

    Now we can extract the "head" companies like this:

    List<Company> companiesHeads = childToParent.entrySet().stream()
            .filter(childIdToParentId -> childIdToParentId.getKey().equals(childIdToParentId.getValue()))
            .map(Map.Entry::getKey)
            .map(idToCompany::get)
            .collect(Collectors.toList());
    

    And print to the screen in JSON format:

    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    System.out.println(mapper.writeValueAsString(companiesHeads));
    

    Output:

    [ {
      "id" : 1,
      "child" : [ {
        "id" : 2,
        "child" : [ {
          "id" : 4
        }, {
          "id" : 5
        } ]
      }, {
        "id" : 3
      } ]
    } ]