Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get filtered JSON nodes through Gson?

Tags:

json

gson

I am using Gson to parse and write JSON data.

[{
    "Source":"IN",
    "Type":"PRD",
    "Name":"ABC"
    "IsActive":true
}, {
    "Source":"IN",
    "Type":"COB",
    "Name":"XYZ"
    "IsActive":true
}, {
    "Source":"PRo",
    "Type":"RPT",
    "Name":"TEST"
    "IsActive":true
}]

How can I get the JSON node based on some attribute values? For example, I wanted to get a node whose values are Source=PRo, Type=RPT and Name=TEST.

How can i do it with Gson?

like image 575
Pavan Tiwari Avatar asked Apr 04 '17 07:04

Pavan Tiwari


1 Answers

As I said above, Gson is not a querying library. But there are at least four strategies you can use with Gson here:

  • Use in-memory strategies
    • Use JSON tree model
    • Use dynamic mappings
    • Use static mappings
  • Use streaming strategy

Each of the above has its own advantages and disadvantages. Applying some modifications to particular nodes is a trivial filter-and-then-forEach problem, and can be solved very easy either with imperative for/if or using Java 8 Stream API.

JSON tree model

JSON tree models are used to build a JSON representation of a particular JSON document in memory. Having a DOM-like structure, you can traverse and modify any tree leaf easily. However, it requires a lot of memory.

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final JsonArray rows = jsonParser.parse(reader).getAsJsonArray();
    StreamSupport.stream(rows.spliterator(), false)
            .map(JsonElement::getAsJsonObject)
            .filter(jsonObject -> jsonObject.get("Source").getAsString().equals("PRo")
                    && jsonObject.get("Type").getAsString().equals("RPT")
                    && jsonObject.get("Name").getAsString().equals("TEST")
            )
            .forEach(jsonObject -> jsonObject.add("IsActive", new JsonPrimitive(false)));
    System.out.println(rows);
}

JSON mapped to Map<String, Object>

Similar to the above, but the rows structure is not even bound with Gson JSON tree model API, thus values can be of any types literally.

private static final Gson gson = new Gson();

private static final Type rowListType = new TypeToken<List<Map<String, Object>>>() {
}.getType();

...

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final List<Map<String, Object>> rows = gson.fromJson(reader, rowListType);
    rows.stream()
            .filter(r -> r.get("Source").equals("PRo")
                    && r.get("Type").equals("RPT")
                    && r.get("Name").equals("TEST"))
            .forEach(r -> r.put("IsActive", false));
    System.out.println(gson.toJson(rows, rowListType));
}

JSON mapped to custom mappings (plain old Java objects)

final class Row {

    @SerializedName("Source")
    String source;

    @SerializedName("Type")
    String type;

    @SerializedName("Name")
    String name;

    @SerializedName("IsActive")
    boolean isActive;

}
private static final Gson gson = new Gson();

private static final Type rowListType = new TypeToken<List<Row>>() {
}.getType();

...

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final List<Row> rows = gson.fromJson(reader, rowListType);
    rows.stream()
            .filter(r -> "PRo".equals(r.source) && "RPT".equals(r.type) && "TEST".equals(r.name))
            .forEach(r -> r.isActive = false);
    System.out.println(gson.toJson(rows, rowListType));
}

Streaming

Streaming allows to read JSON token by token and make some kind of analysis. Since streaming does not require the whole document to be stored in memory, it can even process infinite streams, however it may look a bit harder to use.

private static final Gson gson = new Gson();

...

final TypeAdapter<JsonObject> jsonObjectTypeAdapter = gson.getAdapter(JsonObject.class);
final Writer writer = new StringWriter();
try ( final JsonReader jsonReader = new JsonReader(getPackageResourceReader(Q43200432.class, "q43200432.json"));
      final JsonWriter jsonWriter = new JsonWriter(writer) ) {
    jsonReader.beginArray();
    jsonWriter.beginArray();
    while ( jsonReader.hasNext() ) {
        final JsonObject jsonObject = jsonObjectTypeAdapter.read(jsonReader);
        if ( jsonObject.get("Source").getAsString().equals("PRo")
                && jsonObject.get("Type").getAsString().equals("RPT")
                && jsonObject.get("Name").getAsString().equals("TEST") ) {
            jsonObject.add("IsActive", new JsonPrimitive(false));
        }
        jsonObjectTypeAdapter.write(jsonWriter, jsonObject);
    }
    jsonReader.endArray();
    jsonWriter.endArray();
}
System.out.println(writer);

All four strategies above produce the following output:

[{"Source":"IN","Type":"PRD","Name":"ABC","IsActive":true},{"Source":"IN","Type":"COB","Name":"XYZ","IsActive":true},{"Source":"PRo","Type":"RPT","Name":"TEST","IsActive":false}]

Note that the last element located at $[2].IsActive is set to false.

like image 136
Lyubomyr Shaydariv Avatar answered Oct 17 '22 03:10

Lyubomyr Shaydariv