Arsalan Ahmed
Arsalan Ahmed

Reputation: 383

How do I make nested JSON Objects using 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;
}

Upvotes: 7

Views: 11662

Answers (3)

Christoph Schranz
Christoph Schranz

Reputation: 915

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.

Upvotes: 3

Arsalan Ahmed
Arsalan Ahmed

Reputation: 383

For the record, this is what i did.

import java.util.*;


public class DataObject {

public int Suggestions;
HashMap<String, route> routes = new HashMap<>();

    //constructor
    public DataObject(int mkr, String[][] routesArr){
        Suggestions = mkr;
        { 
            for (int i=0;i<Suggestions;i++){
                routes.put("rank_"+(i+1),new route(routesArr[i]));
            }
        }
    }     
//class to populate the hashmap
public class route{
    public String Origin;
    public String Destination;
    public String Weight; 


public route(String arr[]){
    String[] splitter = arr[0].split("-");
    this.Origin = splitter[0];
    this.Destination = splitter[1];
    this.Weight = arr[1];
}     

}
}

Upvotes: 0

durron597
durron597

Reputation: 32323

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"
    }
  ]
}   

Upvotes: 3

Related Questions