0

lets say I have an array of strings which represents a package-structure. It looks like this:

Array {
  "com.project.server",
  "com.project.client",
  "com.project.client.util",
  ...
}

Its not defined how many levels one package can contain.

Now I want to convert this into an hierarchical JSON-Object. This should look like this:

{
    "name": "com",
    "children": [
        {
            "name": "project",
            "children": [
                {
                    "name": "server"
                }, 
                {
                    "name": "client",
                    "children": [
                        {
                            "name": "util"
                        }
                    ]
                }
            ]
        }
    ]
}

I hope you can understand what I want.

To be honest, I am hopelessly questioned...

Can you help me? Thanks and sorry for possible bad english.

Simon F
  • 13
  • 3

4 Answers4

0

There you go !

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class ParseTree {

    public PackageInfo getRoot(List<String> packages) throws JsonProcessingException {
        Map<String, PackageInfo> map = new HashMap<>();

        String root = null;
        for (String packageName : packages) {
            String[] split = packageName.split("\\.");
            for (int i = 0; i < split.length; i++) {
                String singlePackage = split[i];
                if (root == null) {
                    root = singlePackage;
                }
                map.computeIfAbsent(singlePackage, PackageInfo::new);
                if (i - 1 >= 0) {
                    PackageInfo currentPackage = map.get(singlePackage);
                    map.get(split[i - 1]).getChildren().add(currentPackage);
                }
            }
        }

        return map.get(root);
    }

    public static void main(String[] args) throws JsonProcessingException {
        List<String> packages = Arrays.asList("com.project.server",
            "com.project.client",
            "com.project.client.util", "com.project.client.util.some");

        ParseTree parseTree = new ParseTree();
        PackageInfo root = parseTree.getRoot(packages);
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(root));
    }
}

class PackageInfo {

    private String name;
    private Set<PackageInfo> children;

    public PackageInfo(String name) {
        this.name = name;
        children = new HashSet<>();
    }

    public Set<PackageInfo> getChildren() {
        return children;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        PackageInfo that = (PackageInfo) o;
        return Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name);
    }

    @Override
    public String toString() {
        return "PackageInfo{" +
            "name='" + name + '\'' +
            ", children=" + children +
            '}';
    }
}

It will get you the output as

{
   "name":"com",
   "children":[
      {
         "name":"project",
         "children":[
            {
               "name":"server",
               "children":[

               ]
            },
            {
               "name":"client",
               "children":[
                  {
                     "name":"util",
                     "children":[
                        {
                           "name":"some",
                           "children":[

                           ]
                        }
                     ]
                  }
               ]
            }
         ]
      }
   ]
}
Yogesh Badke
  • 4,249
  • 2
  • 15
  • 23
  • Thanks a lot for your efforts, it looks great and I will try to use it. Unfortunately, I cant use Java 1.8 currently, so I have to change the part with "map.computeIfAbsent(singlePackage, PackageInfo::new)". Any ideas for 1.7? – Simon F Mar 13 '18 at 09:51
  • if (!map.contains(singlePackage)) { map.put(singlePackage, new PackageInfo(singlePackage)) } – Yogesh Badke Mar 13 '18 at 10:34
0

It sounds like you need a Tree structure in Java. There have been multiple solutions discussed here.

You could then convert the input/output JSON in the standard fashion.

RBH
  • 261
  • 1
  • 10
0

For your specific problem with packages, consider using a tree like implementation. You can make the tree only containing unique nodes. This will allow you to get your data into the right format. Here is some pseudo code as on how to create a tree like you want it:

class Tree
    Tree[] children
     String data;

Now to add stuff to this tree you just traverse it like a linked list, meaning you add methods to access the children by number. Furthermore, when you add the nodes make sure they are unique, by comparing them to the already present nodes on the level you're adding it. Since you are more focused on the actual conversion into Json from the Tree.

A possible algorithm is to recursively traverse the tree and create a String from it like this:

public String getJsonFormat(Tree root){
for(Tree child : root.getChildren())
    {
        return "{\n\"name\":\"" + child.data + "\",  \n\"children\":[\n" + getJsonFormat(child) + "\n}"
    }

Now that gives you the Json, which you can now use. For adding stuff to the tree here is an algorithm on how to do it.

addStuffToTree(String packagePath)
    {
     array = packagePath.split("\\.");
     //We now know that the elements in the array, correspond to the level of the tree they are supposed to be in, therefore:
    Tree temp = root; //new Tree which is equal to your root
     if(temp.data != array[0])
    for( i=1; i < array.length; i++){
        for(Tree tree : temp.getChildren())
            if(tree.data == array[i])
                 {temp=tree;
                 i++;
                 // We will traverse the tree like this, avoiding duplicates
                  }
         temp.add(array[i])
         temp = newest child
          //This adds a node if it hasn't been there yet if there are more iterations, it will continue running under that node, if not it will exit the loop
    }

Sorry for this not being pretty, made on my phone.

MrDeal
  • 373
  • 2
  • 11
0

Not too different from other solutions, but since I did it, here you are

@Data
public class Node {
    String name;
    List<Node> children;
    public Node(String name) {
        this.name = name;
        children = new ArrayList<>();
    }
}

public static void main(String[] args) {
    List<String> a = Arrays.asList(
            "com.project.server",
            "com.project.client",
            "com.project.client.util"
        );
    List<Node> root = new ArrayList<>();
    for (String s: a) {
        List<String> packs = Arrays.asList(s.split("\\."));
        List<Node> current = root;
        for (String pack : packs) {
            Optional<Node> newCur = current.stream().filter(node -> node.name.equals(pack)).findFirst();
            if (newCur.isPresent()) {
                current = newCur.get().children;
            } else {
                Node newNode = new Node(pack); 
                current.add(newNode);
                current = newNode.children;
            }
        }
    }
    System.out.println(root);
}

The json conversion should be pretty standard from there

Output using lomboks generated toString:

[Node(name=com, children=[Node(name=project, children=[Node(name=server, children=[]), Node(name=client, children=[Node(name=util, children=[])])])])]
Jan Larsen
  • 831
  • 6
  • 13