Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make nested JSON Objects using Gson?

Tags:

java

json

gson

I have written a program that does some probability calculations and gives its results in the form of arrays. I want to convert these results to JSON format, but I am having issues.

I want my json object to look like this:

{
    "totalSuggestions": 6,
    "routes": {
        "rank_2": {
            "Source": "ABC",
            "Weight": "0.719010390625",
            "Destination": "XYZ"
        },
        "rank_1": {
            "Source": "XYZ",
            "Weight": "0.7411458281249999",
            "Destination": "ABC"
        },
        "rank_0": {
            "Source": "LMN",
            "Weight": "0.994583325",
            "Destination": "PQR"
        }
     }
}   

What I understood is that I need to have an object class with the structure of my objects. For now I am experimenting with the rank object only but failing to form the required JSON.

My code for the object structure:

public class Object {
    int rank_;

    public class Inner{
        String Source;
        String Destination;
        String Weightage;
    }
}

I can pass either an instance of Object or an instance of Inner to toJson() method so I either get {"rank_":1} or {"Source":"ABC","Destination":"XYZ","Weightage":"123"}. I cant seem to put each of the inner object to the corresponding rank object.

I did it with relative ease with org.json but that library has some issues with Android studio so I had to switch to Gson. What I did earlier (which worked as well) was:

public JSONObject convertToJson(int mkr, String[][] result){
    JSONObject outerObj = new JSONObject();
    JSONObject innerObj = new JSONObject();
    JSONObject[] temp = new JSONObject[mkr];
    outerObj.put("totalSuggestions", marker); 
    outerObj.put("routes",innerObj);

    for (int i=0;i<marker;i++){ 
       String[] useless = result[i][0].split("-"); 
       temp[i]= new JSONObject();
       temp[i].put("Source",useless[0] );
       temp[i].put("Destination", useless[1]);
       temp[i].put("Weight", result[i][1]);
       innerObj.put("rank_"+i, temp[i]);
    }
    System.out.println(outerObj.toString());
    return outerObj;
}
like image 633
Arsalan Ahmed Avatar asked Aug 06 '15 10:08

Arsalan Ahmed


People also ask

Can you nest objects in JSON?

Objects can be nested inside other objects. Each nested object must have a unique access path. The same field name can occur in nested objects in the same document.

What is nesting JSON?

Nested JSON is simply a JSON file with a fairly big portion of its values being other JSON objects. Compared with Simple JSON, Nested JSON provides higher clarity in that it decouples objects into different layers, making it easier to maintain.


2 Answers

Well, first: related objects should probably be in a class together. So lets start with a simple class:

public class Results {
  int mkr;
  String[][] result;
}

Now we want to serialize it. We could construct a different data structure, or we could just write our own custom serializer. We want to have our custom class to allow us to use Gson's type inference for doing so, plus the code is just easier to understand. I will show you how to serialize the data structure, and I'll leave the deserialization as an exercise for you.

We create a TypeAdapter<Results>:

public class ResultsAdapter extends TypeAdapter<Results> {
  public Results read(JsonReader reader) throws IOException {
    if (reader.peek() == JsonToken.NULL) {
      reader.nextNull();
      return null;
    }
    // exercise for you
    return results;
  }
  public void write(JsonWriter writer, Results value) throws IOException {
    if (value == null) {
      writer.nullValue();
      return;
    }
    writer.beginObject();
    writer.name("totalSuggestions").value(value.mkr);
    writer.name("routes");
    writer.beginObject();
    for(int i = 0; i < value.mkr; i++) {
       writer.name("rank_"+i);
       writer.beginObject();
       String[] sourceDestSplit = result[i][0].split("-"); 
       writer.name("Source").value(sourceDestSplit[0]);
       writer.name("Destination").value(sourceDestSplit[1]);
       writer.name("Weight").value(result[i][1]);
       writer.endObject();
    }
    writer.endObject();
    writer.endObject();
  }
}

You can then call this method by doing (note: should only create the Gson object once, but I did it this way to keep the code short):

public String convertToJson(Results results) {
   GsonBuilder builder = new GsonBuilder();
   builder.registerTypeAdapter(new ResultsAdapter()):
   Gson gson = builder.build();

   return gson.toJson(results);
}

This will work you the way you've asked, but I strongly recommend using JSON's array syntax instead (using []). Try this instead:

  public void write(JsonWriter writer, Results value) throws IOException {
    if (value == null) {
      writer.nullValue();
      return;
    }
    writer.beginObject();
    writer.name("totalSuggestions").value(value.mkr);
    writer.name("routes");
    writer.beginArray();
    for(int i = 0; i < value.mkr; i++) {
       writer.beginObject();
       String[] sourceDestSplit = result[i][0].split("-"); 
       writer.name("Source").value(sourceDestSplit[0]);
       writer.name("Destination").value(sourceDestSplit[1]);
       writer.name("Weight").value(result[i][1]);
       writer.endObject();
    }
    writer.endArray();
    writer.endObject();
  }

Doing it this will will result in JSON that looks like this, which will be easier to deserialize on the other side and iterate through, because you won't have to dynamically generate maps for the keys.:

{
  "totalSuggestions": 6,
  "routes": [
    {
        "Source": "ABC",
        "Weight": "0.719010390625",
        "Destination": "XYZ"
    },
    {
        "Source": "XYZ",
        "Weight": "0.7411458281249999",
        "Destination": "ABC"
    },
    {
        "Source": "LMN",
        "Weight": "0.994583325",
        "Destination": "PQR"
    }
  ]
}   
like image 59
durron597 Avatar answered Nov 18 '22 16:11

durron597


I landed here while searching for a similar solution for the com.google.gson.JsonObject library. Now, I've found it:

JsonObject mainJson = new JsonObject();
JsonObject innerJson = new JsonObject();

innerJson.addProperty("@iot.id", "31");
mainJson.add("Datastream", innerJson);  // <-- here the nesting happens
mainJson.addProperty("result", 12.3);

// fetch inner variable like this
System.out.println(mainJson.get("Datastream").getAsJsonObject().get("@iot.id").getAsString());

This works fine for me using the com.google.gson.JsonObject library.

like image 21
Christoph Schranz Avatar answered Nov 18 '22 15:11

Christoph Schranz