Gson's missing get element function - Part II


The Gson missing recursive get function - Review.


A while back, probably more than a year ago, I wrote an article Gson's Missing recursive get function 
where I discussed the shortcomings of the current gson get function, whereby it only traverses top-level entry key for the search key.

In this article I'll introduce a new functionality that allows for even deeper traversal of same name nodes until a primitive value is found (if needed).

{
    "result" : {
        "total_items" : 1,
        "total_pages" : 1,
        "items_per_page" : 25,
        "current_page" : 1,
        "items" : {
                "username" : "test",
                "items" : {
                  items: "12345"
                },
                "secret" : "",
                "application" : {
                    "name" : "test app"
                }
            }
    },
    "error" : null,
    "id" : 1
}


Above I have given an example whereby the key items is nested (3 items key) . Suppose we wish to search for the items object with the previous recursive get functionality ?

It would be something like this :


import static GsonUtil.*
// assumption here is that a static import is done. ignoring the GsonUtils for space reasons
get("items", get("item", get("items", response).getAsJsonObject()).getAsJsonObject()).getAsString()


That's a problem. Of course one can see that the more nested the json is the more error problem it is to get the value needed. 

The workaround was to implement a deep traversal mechanism inside the current implementation that would iterate until a primitive type was found.

import java.util.Map.Entry;
import java.util.Set;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;


public class GsonUtil {

    /**
     * The following function does a top-down recursive descent on a json tree to
     * find an element with-in structure
     *
     * @param value : value to retrieve
     * @param jObj : json object to traverse
     * @return JsonElement if found or null if element not found
     */ 
    public JsonElement get(String value, JsonObject jObj) {
        return get(value, jObj, false);
    }

    /**
     * The following function does a top-down recursive descent on a json tree to
     * find an element with-in structure
     *
     * @param value : value to retrieve
     * @param jObj : json object to traverse
     * @param deep : determines if object should be traversed further until a primitive is found
     * @return JsonElement if found or null if element not found
     */
    public JsonElement get(String value, JsonObject jObj, boolean deep) {

        // check current level for the key before descending
        if (jObj.isJsonObject() && jObj.has(value)) {
            if(deep) {
                if(jObj.isJsonPrimitive() || jObj.get(value).isJsonPrimitive())
                    return jObj.get(value);
                return get(value, jObj.get(value).getAsJsonObject(), true);
            } else return jObj.get(value);
        }


        // get all entry sets
        Set<Entry<String, JsonElement>> entries = jObj.entrySet();
       
        for (Entry<String, JsonElement> entry : entries) {
           
            // cache the current value since retrieval is done so much
            JsonElement curVal = entry.getValue();
           
            if (curVal.isJsonArray()) {
                for (JsonElement el : curVal.getAsJsonArray()) {
                    // recursively traverse the sub-tree
                    JsonElement res = get(value, el.getAsJsonObject(), deep);
                    if (res != null)
                        return res;
                }
            } else if (curVal.isJsonObject()) {
                // traverse sub-node
                return get(value, curVal.getAsJsonObject(), deep);
            }
        }
        return (deep) ? jObj : null;
    }
}

Refactor:


import static GsonUtil.*
// assumption here is that a static import is done. ignoring the GsonUtils for space reasons
get("items", get("item", get("items", response).getAsJsonObject()).getAsJsonObject()).getAsString()

Becomes:
get("items", response, true).getAsString()

The above method solves the short-comings of the previous get method. The above method allows a third parameter to be passed to the function. The third param allows for for further traversal of objects that aren't primitive.

Comments

Popular posts from this blog

JavaScript Module Pattern: 2 Forms

Pseudo-Random UUID Generation with mask support

Mocking Ajax with the JQuery Mockjax Library