Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flattening a JSONObject in Java - Recursion causing StackOverflowError

I've been writing a method to "flatten" a codehaus JSONObject in Java. Unfortunately, I'm seeing a StackOverflowError in the recursion through the object nests, but I'm finding it difficult to debug. Here is the error I'm seeing:

Exception in thread "main" java.lang.StackOverflowError
    at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
    at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
    at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
    at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
    at java.util.LinkedHashMap.newKeyIterator(LinkedHashMap.java:396)
    at java.util.HashMap$KeySet.iterator(HashMap.java:874)
    at org.codehaus.jettison.json.JSONObject.keys(JSONObject.java:533)
    at org.codehaus.jettison.json.JSONObject.toString(JSONObject.java:1079)
    at org.codehaus.jettison.json.JSONObject.valueToString(JSONObject.java:1210)

I'm using Iterator to loop the keys, and using hasNext() and next() to ensure that I should only be able to access specific object keys.

I started testing with a simple JSONObject of:

JSONObject json = new JSONObject("outer":{"field1":"value","inner":{"field2":12345,"field3":"[email protected]"}});

/*
"outer":{
    "field1":"value",
    "inner":{
        "field2":12345,
        "field3":"[email protected]"
    }
}
*/

This should result in a single nest containing fields1|2|3.

Here is the code I have so far:

private static JSONObject flatten(JSONObject object, JSONObject flattened){
    if(flattened == null){
        flattened = new JSONObject();
    }
    Iterator<?> keys = object.keys();
    while(keys.hasNext()){
        String key = (String)keys.next();
        try {
            if(object.get(key) instanceof JSONObject){
                flattened.put(key, flatten(object.getJSONObject(key), flattened));
            } else {
                flattened.put(key, object.get(key));
            }
        } catch(JSONException e){
            System.out.println(e);
        }
    }
    return flattened;
}

I have been debugging this for a while now, but haven't been able to make any headway - so I'd appreciate any pointers with this. Thanks in advance for any help - if any more info is needed, just leave a comment.

like image 579
whitfin Avatar asked Sep 01 '25 20:09

whitfin


2 Answers

Replace

flattened.put(key, flatten(object.getJSONObject(key), flattened));

by

flatten(object.getJSONObject(key), flattened);

Here it gives me {"field1":"value","field2":12345,"field3":"[email protected]"} and I think that's what you want

Notice that when you call the function recursively, you pass the "flattened" object into the function, and then it returns it back to you, which you then add to "flattened". Thus you are adding the object to itself, creating a circular reference

When you do the recursive call, don't add the result back into the object. Just do:

flatten(object.getJSONObject(key), flattened);
like image 23
ldkronos Avatar answered Sep 03 '25 11:09

ldkronos