Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursively building a JSON string to jsTree with Jackson

I´ve been trying to build a JSON string in Java using the Jackson library (v.1.7.4, it´s the only one I can use for this project) to the format accepted by jsTree (https://www.jstree.com/docs/json/). I only care about the "text" and "children" properties. Problem is, I´m not getting a working recursive method to do so.

If I have a simple Tree like this one:

    Tree<String> tree = new Tree<String>();
    Node<String> rootNode = new Node<String>("root");
    Node<String> nodeA = new Node<String>("A");
    Node<String> nodeB = new Node<String>("B");
    Node<String> nodeC = new Node<String>("C");
    Node<String> nodeD = new Node<String>("D");
    Node<String> nodeE = new Node<String>("E");

    rootNode.addChild(nodeA);
    rootNode.addChild(nodeB);
    nodeA.addChild(nodeC);
    nodeB.addChild(nodeD);
    nodeB.addChild(nodeE);

    tree.setRootElement(rootNode);

I´d expect my String to be:

 {text: "root", children: [{text:"A", children:[{text:"C", children: []}]}, {text:"B", children: [{text: "D", children: []}, {text:"E", children:[]}]}] }

I´m trying to build the JSON string using the Tree Model from Jackson. My code so far looks something like this:

 public String generateJSONfromTree(Tree<String> tree) throws IOException{
    String json = "";

    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = new JsonFactory();
    ByteArrayOutputStream out = new ByteArrayOutputStream(); // buffer to write to string later
    JsonGenerator generator = factory.createJsonGenerator(out, JsonEncoding.UTF8);

    JsonNode rootNode = mapper.createObjectNode();
    JsonNode coreNode = mapper.createObjectNode();          

    JsonNode dataNode = (ArrayNode)generateJSON(tree.getRootElement()); // the tree nodes

    // assembly arrays and objects
    ((ObjectNode)coreNode).put("data", dataNode);
    ((ObjectNode)rootNode).put("core", coreNode);       
    mapper.writeTree(generator, rootNode);

    json  = out.toString();
    return json;
}

 public ArrayNode generateJSON(Node<String> node, ObjectNode obN, ArrayNode arrN){
    // stop condition ?
    if(node.getChildren().isEmpty()){
        arrN.add(obN);
        return arrN;
    }

    obN.put("text", node.getData());
    for (Node<String> child : node.getChildren()){

        // recursively call on child nodes passing the current object node
        obN.put("children", generateJSON(child, obN, arrN));
    }

}

I tried a few variations of that but no success so far. I know the answer is probably simpler than I´m trying, but I´m stuck. Maybe the stop condition is not appropriate or the logic itself (my thought is to try and reuse the ObjectNode and ArrayNode objects on the next call, to "insert" the "children" element (from the json) on the next child node on the tree, so it would be built backwards, but in the end I get null variables ).

My tree and node classes are based on the following : http://sujitpal.blogspot.com.br/2006/05/java-data-structure-generic-tree.html

like image 351
Pedro Avatar asked Nov 09 '15 20:11

Pedro


People also ask

How does Jackson build JSON?

We can create a JSON in the Jackson library using the JsonNodeFactory, it can specify the methods for getting access to Node instances as well as the basic implementation of the methods. We can use the set() and put() methods of ObjectNode class to populate the data.

How does Jackson read nested JSON?

A JsonNode is Jackson's tree model for JSON and it can read JSON into a JsonNode instance and write a JsonNode out to JSON. To read JSON into a JsonNode with Jackson by creating ObjectMapper instance and call the readValue() method. We can access a field, array or nested object using the get() method of JsonNode class.

How does ObjectMapper read JSON data?

Read JSON file into Object using ObjectMapper. To read JSON file into java object, Jackson provides ObjectMapper. readValue(). Find the input JSON file. Now find the java class to read the JSON.


1 Answers

Not the best approach, but it gets the job done:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class TreeApp {

    public String generateJSONfromTree(Tree<String> tree) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        JsonFactory factory = new JsonFactory();
        ByteArrayOutputStream out = new ByteArrayOutputStream(); // buffer to write to string later
        JsonGenerator generator = factory.createJsonGenerator(out, JsonEncoding.UTF8);

        ObjectNode rootNode = generateJSON(tree.getRootElement(), mapper.createObjectNode());
        mapper.writeTree(generator, rootNode);

        return out.toString();
    }

    public ObjectNode generateJSON(Node<String> node, ObjectNode obN) {
        if (node == null) {
            return obN;
        }

        obN.put("text", node.getData());

        ArrayNode childN = obN.arrayNode();
        obN.set("children", childN);        
        if (node.getChildren() == null || node.getChildren().isEmpty()) {
            return obN;
        }

        Iterator<Node<String>> it = node.getChildren().iterator();
        while (it.hasNext()) {  
            childN.add(generateJSON(it.next(), new ObjectMapper().createObjectNode()));
        }
        return obN;
    }

    public static void main(String[] args) throws IOException {
        Tree<String> tree = new Tree<String>();
        Node<String> rootNode = new Node<String>("root");
        Node<String> nodeA = new Node<String>("A");
        Node<String> nodeB = new Node<String>("B");
        Node<String> nodeC = new Node<String>("C");
        Node<String> nodeD = new Node<String>("D");
        Node<String> nodeE = new Node<String>("E");

        rootNode.addChild(nodeA);
        rootNode.addChild(nodeB);
        nodeA.addChild(nodeC);
        nodeB.addChild(nodeD);
        nodeB.addChild(nodeE);

        tree.setRootElement(rootNode);

        System.out.println(new TreeApp().generateJSONfromTree(tree));
    }
}
like image 102
Tomas Zezula Avatar answered Nov 01 '22 19:11

Tomas Zezula