deserializing a JSON object with multiple items inside it

android, gson, java, json

Solution

This is an example of data that probably should have been serialized as an array, but was not. One solution to parsing it is to utilize a `JSONObject` directly.

String json = ...;
final Gson gson = new Gson();

final List<Attachment> attachements = new ArrayList<Attachment>(64);
final JSONObject jsonObj = new JSONObject(json).getJSONObject("attachments");
final Iterator<String> keys = jsonObj.keys();
while(keys.hasNext()) {
    final String key = keys.next();
    attachements.add(gson.fromJson(jsonObj.getJSONObject(key).toString(), Attachment.class);
}

// Do something with attachements

The data can also be viewed as a map, of id's to attachments. And it can be deserialized as such:

final String jsonObj = new JSONObject(json).getJSONObject("attachments");
final Gson gson = new Gson();
final Map<String, Attachment> data = gson.fromJson(jsonObj.toString(),
        new TypeToken<Map<String, Attachment>>() {
        }.getType());
final List<Attachment> attachments = new ArrayList<Attachment>(data.values());

This is actuall

Problem

I'm trying to deserialize (using gson) a JSON object that looks like this: ``` "attachments": { "40": { "ID": 40, "URL": "http:\/\/drewmore4.files.wordpress.com\/2013\/02\/wreckit.jpg", "guid": "http:\/\/drewmore4.files.wordpress.com\/2013\/02\/wreckit.jpg", "mime_type": "image\/jpeg", "width": 287, "height": 400 }, "3": { "ID": 3, "URL": "http:\/\/drewmore4.files.wordpress.com\/2013\/02\/frankenweenie2bposter.jpg", "guid": "http:\/\/drewmore4.files.wordpress.com\/2013\/02\/frankenweenie2bposter.jpg", "mime_type": "image\/jpeg", "width": 273, "height": 400 } }, ``` How do I handle it? I don't even know what to call this - There are multiple "items" represented here, but it's not an array. When I try to deserialize it as an array, the program crashes on a "Expected Begin_Array but found Begin_Object" exception. When I try to deserialize it as a Strong object (see class below), the program runs but the fields all return null. Here is the class I've tried to map it to: ``` class Attachment { int ID; String URL; } ``` the full JSON file can be seen here: EDIT: SOLVED. @Perception's solution basically worked. It was complicated by the fact that this "element" (still would like to know what this multiple-entry/non-array json element) is embedded in a larger json object that does contain an array. Again, this JSON is not my design - it comes from the Wordpress REST API, and (as @Perception alluded to), I think the issue I've had illustrates a design flaw in it - namely that the attachments element should be an array, rather than a single object. Nonetheless, Nonetheless, if anyone else ever needs to deserialize the result of a query for all posts on a given site using this API, and further needs access to the attachments on each post, here's how you do it: ``` private class getAll extends AsyncTask <Void, Void, JSONObject> { private static final String url = "https://public-api.wordpress.com/rest/v1/sites/drewmore4.wordpress.com/posts/"; @Override protected JSONObject doInBackground(Void... params) { HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet(url); httpget.addHeader("accept", "application/json"); JSONObject returned = new JSONObject(); HttpResponse response; try { response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); String result= convertStreamToString(instream); returned =new JSONObject(result); instream.close(); } } catch (ClientProtocolException | IOException | JSONException e) { e.printStackTrace();} return returned; } @Override protected void onPostExecute (JSONObject returned){ Gson gson = new Gson(); //posts is the element within the JSONObject that is an array of post objects try { JSONArray posts = returned.getJSONArray("posts"); for (int curr = 0; curr < posts.length(); curr++){ String s = posts.get(curr).toString(); Article a = gson.fromJson(s, Article.class); JSONObject attachments = new JSONObject(s).getJSONObject("attachments"); final Iterator<String> keys = attachments.keys(); while(keys.hasNext()) { final String key = keys.next(); a.attached.add(gson.fromJson(attachments.getJSONObject(key).toString(), Attachment.class)); } stories.add(a); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } ```

Original source