Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse a JSON with dynamic “key” in android by using GSON

Tags:

android

gson

I have been using GSON library to parse all the json string and get a JSON object. But now I need to parse is like this:

{
   "status":1,
   "info":[
      {
         "\u5a31\u4e50":"\u51b7\u76d8,\u9ad8\u811a\u676f,\u6211\u7684\u7cd6\u679c\u5c4b,\u670d\u52a1\u4e1a\u6d88\u8d39\u52b5"
      },
      {
         "\u7f8e\u5986":"\u4e2a\u62a4|\u5316\u5986#\u9762\u90e8\u62a4\u7406,\u4e2a\u4eba\u536b\u751f,\u8eab\u4f53\u62a4\u7406,\u9999\u6c34\u9999\u6c1b,\u6c90\u6d74|\u7f8e\u53d1\u7528\u54c1,\u5f69\u5986,\u7cbe\u6cb9SPA,\u773c\u90e8\u62a4\u7406,\u78e8\u7802\u53bb"
      },
      {
         "\u8863\u670d":"\u670d|\u9970|\u978b|\u5e3d#\u670d\u88c5,\u978b\u9774,\u5185\u8863,\u914d\u9970,\u536b\u8863,\u4f11\u95f2\u88e4,T\u6064,\u88d9\u5b50,\u886c\u886b,\u9488\u7ec7\u886b,\u5a74\u5e7c\u513f\u670d\u9970"
      }
   ],
   "total":3
}

The key fields are dynamic, so I don't know how to write a model class to read this.

like image 960
gulin Avatar asked Apr 22 '12 11:04

gulin


People also ask

How does GSON read JSON?

Reading and writing JSON using GSON is very easy. You can use these two methods: toJSON() : It will convert simple pojo object to JSON string. FromJSON() : It will convert JSON string to pojo object.

What is GSON and JSON in Android?

Gson is a Java library that can be used to convert Java objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including objects for which you do not have the source.

What is JSONPath parse?

JSONPath is an expression language to parse JSON data. It's very similar to the XPath expression language to parse XML data. The idea is to parse the JSON data and get the value you want. This is more memory efficient because we don't need to read the complete JSON data.


2 Answers

How would you like your model class to look?

status and total would probably be int, so that only leaves info.

As an experiment, just add a field Object info and see how Gson would set it to an ArrayList<LinkedHashMap<String, String>> -- ugly and hard to access by key, but all the data is there. Given that information, the fastest way to model a class would be:

class Something {
  int status;
  List<Map<String, String> info;
  int total;
}

If you have control over how that JSON is generated, I suggest changing the structure of info from an array of objects [{a:b},{c:d},{e:f}] to just an object {a:b,c:d,e:f}. With this, you could just map it to a Map<String, String> with all the benefits like access by key, keys() and values():

class Something {
  int status;
  Map<String, String> info;
  int total;
}

If you want the latter model class without changing the JSON format, you'll have to write a TypeAdapter (or JsonDeserializer if you're only interested in parsing JSON, not generating it from your model class).

Here's a JsonDeserializer hat would map your original info JSON property to a plain Map<String, String>.

class ArrayOfObjectsToMapDeserializer
    implements JsonDeserializer<Map<String, String>> {

  public Map<String, String> deserialize(JsonElement json, Type typeOfT,
      JsonDeserializationContext context) throws JsonParseException {
    Map<String, String> result = new HashMap<String, String>();

    JsonArray array = json.getAsJsonArray();
    for (JsonElement element : array) {
      JsonObject object = element.getAsJsonObject();
      // This does not check if the objects only have one property, so JSON
      // like [{a:b,c:d}{e:f}] will become a Map like {a:b,c:d,e:f} as well.
      for (Entry<String, JsonElement> entry : object.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue().getAsString();
        result.put(key, value);
      }
    }
    return result;
  }
}

You need to register this custom JsonDeserializer similar to this:

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(
    new TypeToken<Map<String, String>>() {}.getType(),
    new ArrayOfObjectsToMapDeserializer());
Gson gson = builder.create();

Note that this registers the custom deserializer for any Map<String, String> regardless in what class it is encountered. If you don't want this, you'll need to create a custom TypeAdapterFactory as well and check the declaring class before returning and instance of the deserializer.

like image 149
Philipp Reichart Avatar answered Oct 18 '22 13:10

Philipp Reichart


Here goes a solution, which does not requires to make a JsonDeserializer.

All you can create is a JsonElement in a map Map.Entry<String, JsonElement>and use a for loop to iterate over the entries

//parsing string response to json object
JsonObject jsonObject = (JsonObject) new JsonParser().parse(jsonString);
//getting root object
JsonObject dateWiseContent = jsonObject.get("rootObject").getAsJsonObject();
    
for (Map.Entry<String, JsonElement> entry : dateWiseContent.entrySet()) {      
    //this gets the dynamic keys
    String  dateKey = entry.getKey();
            
    //you can get any thing now json element,array,object according to json.
            
    JsonArray jsonArrayDates = entry.getValue().getAsJsonArray();
}

read more here

like image 1
vikas kumar Avatar answered Oct 18 '22 12:10

vikas kumar