Using Gson with a Track

Using a simple Json file like:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

      

I want to get JsonArray

named menuitem

using path:

String path =  "menu.popup.menuitem"

      

I tried to do it using:

public static JsonElement fromString(String json, String path) throws JsonSyntaxException {
        JsonObject obj = GsonBuilder.create().fromJson(json, JsonObject.class);
        String[] seg = path.split(".");
        for (String element : seg) {
            if (obj != null) {
                obj = obj.get(element).getAsJsonObject();
            } else {
                return null;
            }
        }
        return obj
}

      

from:

JsonElement jsonElement = fromString(json, path);

      

But when I try isJsonArray()

, the return value false

. When performing an additional sanity check using the Gson.toJson(jsonElement)

output is the complete json String (above) that was originally entered. What's wrong?

+3


source to share


2 answers


split

uses regex to find where the string should be split, but .

in regex is a special character that represents "any character near line separators", which means you are actually splitting at each character. So for a string like

"foo"

      

"foo".split(".")

will break into f

, o

,o

"foo"
 ^^^

      

which means you get as an array of results with 4 blank lines (3 splits give 4 elements).



["", "", "", ""]

      

Actually I lied because it split(regex)

does one more thing: it removes trailing blank lines from the result array, but your array only contains blank lines, which means they will all be removed, so split(".")

only an empty array will return []

so your loop doesn't repeat even once (which is why your method returns unmodified obj

).

To get rid of this problem, you need to make a literal .

(you need to avoid it). For this you can use, for example, split("\\.")

or split("[.]")

or split(Pattern.quote(".")

, which work the same way split("\\Q.\\E")

- it adds a quote area.

Also inside the loop, you must first check for the Json type you are processing because it getAsJsonObject

will fail if the Json is an array. Therefore your code should look like

public static JsonElement fromString(String json, String path)
        throws JsonSyntaxException {
    JsonObject obj = new GsonBuilder().create().fromJson(json, JsonObject.class);
    String[] seg = path.split("\\.");
    for (String element : seg) {
        if (obj != null) {
            JsonElement ele = obj.get(element);
            if (!ele.isJsonObject()) 
                return ele;
            else
                obj = ele.getAsJsonObject();
        } else {
            return null;
        }
    }
    return obj;
}

      

+3


source


I'm not sure why this is not built into Gson, but here is a method I wrote that returns a JsonElement given the JsonElement input and the JSON path:

/**
 * Returns a JSON sub-element from the given JsonElement and the given path
 *
 * @param json - a Gson JsonElement
 * @param path - a JSON path, e.g. a.b.c[2].d
 * @return - a sub-element of json according to the given path
 */
public static JsonElement getJsonElement(JsonElement json, String path){

    String[] parts = path.split("\\.|\\[|\\]");
    JsonElement result = json;

    for (String key : parts) {

        key = key.trim();
        if (key.isEmpty())
            continue;

        if (result == null){
            result = JsonNull.INSTANCE;
            break;
        }

        if (result.isJsonObject()){
            result = ((JsonObject)result).get(key);
        }
        else if (result.isJsonArray()){
            int ix = Integer.valueOf(key) - 1;
            result = ((JsonArray)result).get(ix);
        }
        else break;
    }

    return result;
}

      



To call it use something like:

String jsonString = ...;

Gson gson = new Gson();
JsonObject  jsonObject = gson.fromJson(jsonString, JsonObject.class);
JsonElement subElement = getJsonElement(jsonObject, "a.b.c[2].d";

      

+2


source







All Articles