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

Mocking Ajax with the JQuery Mockjax Library

JavaScript Module Pattern: 2 Forms

A better JavaScript typeof function