Parse json with mixed child objects via gson and s

2019-07-03 02:47发布

问题:

I'm facing a problem related to parsing json which have mixed arrays of child classes, and I need to provide that as java list back to client.

Sample JSON:

{
  "status": "OK",
  "results": [
    {
      "type": "one",
       "Id": "2170676",
       "count": "456",
       "title": "title",
       "description": "description",
       "oneMemberOne": "11",
       "oneMemberTwo": "12",
    }
    {
      "type": "two",
      "Id": "2170677",
      "count": "123",
      "title": "title",
      "description": "description",
      "twoMemberOne": "21",
      "twoMemberTwo": "22",
    }
  ]
}

I created one Parent class and two child class from this:

Num : type, Id, count, title, description fields

One extends Num : oneMemberOne, oneMemberTwo

Two extends Num : twoMemberOne, twoMemberTwo

Now my question: I have a method for asking results. Say it List<Num> getResults()

  • I parse the data properly like this:

    List<Num> result = new ArrayList<Num>();
    JsonParser parser = new JsonParser();
    JsonObject jsonObject = parser.parse(lastResponsePayload).getAsJsonObject()
    JsonArray results = jsonObject.get("results").getAsJsonArray();
    for (JsonElement element : results) {
         JsonObject trs = element.getAsJsonObject();
         String type = trs.get("type").getAsString();
    
         if (type.equals("one") {
              One one = new Gson().fromJson(element, One.class);
              result.add(product);
         } else if (type.equals("two") {
              Two two = new Gson().fromJson(element, Two.class);
              result.add(metaproduct);
         }
    return result;
    
  • Now, on client side, after I get the list, i have to do this:

    List<Num> results = getResults();
    List<One> oness = new ArrayList<One>();
    List<Two> twoss = new ArrayList<Two>();
    for(Num n : results) {
         if(n.type.equals("one")
              oness.add((One) n);
         else
              twoss.add((Two) n);
    

Is this a good design for this scenario ?

User of this API has to downcast everytime based on the type field of parent class. Because webservice gives me mixed array of child classes, I have to do this. Is there any better approach to this problem ?

  • One another approach in my mind is to create a Result class which contains two members One and Two and provide my a List<Result> instead of List<Num>, but then user has to check whether member is null or not and then take appropriate steps.

Thank you in advance.

回答1:

I will suggest that you have another class something like this. It prevents client code from spinning through list again and parsing out records. Please note I have not run this code to test it.

public class Result {
    private List<One> oness;
    private List<Two> twoss;

    public List<One> getOness() {
        return oness;
    }

    public void setOness(List<One> oness) {
        this.oness = oness;
    }

    public List<Two> getTwoss() {
        return twoss;
    }

    public void setTwoss(List<Two> twoss) {
        this.twoss = twoss;
    }
}

And change

List<Num> getResults()

To

Result getResults()

also user will not have to check for nulls if you modify your parsing logic. Please see that in case we don't have results we are not returning null list but EmptyList.

Result result = new Result();
    JsonParser parser = new JsonParser();
    JsonObject jsonObject = parser.parse(lastResponsePayload).getAsJsonObject()
    JsonArray results = jsonObject.get("results").getAsJsonArray();

    List<One> oness = null;
    List<Two> twoss = null;

    for (JsonElement element : results) {
         JsonObject trs = element.getAsJsonObject();
         String type = trs.get("type").getAsString();

         if (type.equals("one")) {
             if(oness == null) {
                 oness = new ArrayList<One>();
                 result.setOness(oness);
             }
             One one = new Gson().fromJson(element, One.class);
             oness.add(product);
         } else if (type.equals("two")) {
             if(twoss == null) {
                 twoss = new ArrayList<Two>();
                 result.setTwoss(twoss);
             }
              Two two = new Gson().fromJson(element, Two.class);
              twoss.add(metaproduct);
         }
         if(oness == null) {
             result.setOness(Collections.<One>EMPTY_LIST);
         }
         if(twoss == null) {
             result.setTwoss(Collections.<Two>EMPTY_LIST);
         }

    return result;

Hope it helps :)