简体   繁体   中英

Manually parse a portion of dynamic JSON object alongside Gson deserializer

I want to parse the following JSON response with a dynamic JSON object,

{
  "id": 1,
  "last_login": "2016-07-16T12:46:29.621996Z",
  "point_of_sales": [
    {
      "Counter 4": {
        "type": "retail",
        "id": 6
      }
    },
    {
      "Counter 5": {
        "type": "retail",
        "id": 7
      }
    },
    {
      "Counter 6": {
        "type": "retail",
        "id": 8
      }
    }
  ]
}

Here the objects name inside " point_of_sales " array are dynamic which makes it difficult to parse using Gson. Here's what I've tried so far,

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("last_login")
@Expose
private String lastLogin;
@SerializedName("point_of_sales")
@Expose
private List<Map<String, Counter>> pointOfSales = new ArrayList<Map<String, Counter>>();

.......

getter & setters

Counter class,

@SerializedName("type")
@Expose
private String type;
@SerializedName("id")
@Expose
private Integer id;

.......

getter & setters

By following this procedure I can convert the objects but can't extract them from map to the pojo classes.

 for (Map<String, Counter> objectMap : response.getPointOfSales())
{
// How to extract the Counter pojo data from map list?
}

I also tried this way but nothing works,

ArrayList<Counter> pojos = new ArrayList<Counter>();
                    try {
                        for (Map<String, Counter> objectMap : result.getPointOfSales()) {
                            Counter pojo = new Counter();
                            for (Map.Entry<String, Counter> property : objectMap.entrySet()) {
                                Method setter = Counter.class.getMethod("set" + property.getKey().substring(0, 1).toUpperCase() + property.getKey().substring(1), property.getValue().getClass());
                                setter.invoke(pojo, property.getValue());
                            }
                            pojos.add(pojo);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    for (Counter pojo : pojos) {
                        Log.e("result", "" + pojo.getId() + " " + pojo.getType());
                    }

Is there any way to parse the specific array by using,

  1. Gson

  2. Using a duel parsing technique to parse the specific portion manually and rest of the response in Gson?

I want to make the dynamic objects wrapped into a pojo class.

You need two things.

  1. You need to do a little bit of refactoring on your model classes.
  2. You would need to add a JsonDeserializer to handle that dynamic parsing.

Here's how I would do it:

MainObject.java

.....
@SerializedName("point_of_sales")
SalesPoints mSales Points
.....

SalesPoints.java

private List<Counter>mCounters;
//getter & setters.

Counter.java

SerializedName("type")
private String type;
@SerializedName("id")
private int id; // use primitives instead of boxed primitives
private String mCounterString; // maybe you need it.

Now when you will run the parsing you'll have to do something like this:

 MainObject object = new GsonBuilder().registerTypeAdapter(SalesPoints.class, new JsonDeserializer< SalesPoints >() {
        @Override
        public SalesPoints deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            SalesPoints sales = new SalesPoints();
            ArrayList<Counter>counters = new ArrayList<Counter>();
            JsonArray salesJson = json.getAsJsonArray();
            for(JsonElement object : json.getAsJsonArray()) {
                   Iterator<Map.Entry<String,JsonElement>> iterator = object.getAsJsonObject().entrySet().iterator();
                   while (iterator.hasNext())){
                          Map.Entry<String,JsonElement> entry = iterator.next();
                            String counterString = entry.getKey();
                            JsonElement counterObject = 
                                                    entry.getValue();
                            Counter counter = context.deserialize(counterObject, Counter.class);
                            counter.setCounterString(counterString);
                            counters.add(counter);
                        }          
            }
            sales.setCounters(counters);
            return sales;
        }
    }).create().fromJson(theJson);

Now when the MainObject is parsed it will contain the SalesPoints that contains all the counters.

NOTE: I might misspelled some words, or I might forgot to add some getAs.. methods because I didn't have the possibility to test the code, but this is the way to go and you can easily debug it.

EDIT

For retrofit you'll need to do something like this:

Gson gson = new GsonBuilder().registerTypeAdapter(SalesPoints.class, new JsonDeserializer< SalesPoints >() {
        @Override
        public SalesPoints deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            SalesPoints sales = new SalesPoints();
            ArrayList<Counter>counters = new ArrayList<Counter>();
            JsonArray salesJson = json.getAsJsonArray();
            for(JsonElement object : json.getAsJsonArray()) {
                   Iterator<Map.Entry<String,JsonElement>> iterator = object.getAsJsonObject().entrySet().iterator();
                   while (iterator.hasNext())){
                          Map.Entry<String,JsonElement> entry = iterator.next();
                            String counterString = entry.getKey();
                            JsonElement counterObject = 
                                                    entry.getValue();
                            Counter counter = context.deserialize(counterObject, Counter.class);
                            counter.setCounterString(counterString);
                            counters.add(counter);
                        }          
            }
            sales.setCounters(counters);
            return sales;
        }
    }).create();


new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson))//set remaining things fro your retrofit builder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM