【问题标题】:deserializing a JSON object with multiple items inside it反序列化包含多个项目的 JSON 对象
【发布时间】:2013-02-25 05:09:34
【问题描述】:

我正在尝试反序列化(使用 gson)一个如下所示的 JSON 对象:

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

我该如何处理?我什至不知道该怎么称呼它——这里有多个“项目”,但它不是一个数组。当我尝试将其反序列化为数组时,程序因“预期的 Begin_Array 但发现 Begin_Object”异常而崩溃。当我尝试将其反序列化为 Strong 对象时(请参见下面的类),程序运行但所有字段都返回 null。

这是我尝试将其映射到的类:

class Attachment {
int ID;
String URL;
}

完整的JSON文件可见here:

编辑:已解决。

@Perception 的解决方案基本上奏效了。这个“元素”(仍然想知道这个多条目/非数组 json 元素是什么)嵌入到一个更大的包含数组的 json 对象中,这一事实使情况变得复杂。同样,这个 JSON 不是我的设计——它来自 Wordpress REST API,并且(正如@Perception 所暗示的那样),我认为我遇到的问题说明了它的设计缺陷——即附件元素应该是一个数组,而不是单个对象。尽管如此,

尽管如此,如果其他人需要使用此 API 对给定站点上所有帖子的查询结果进行反序列化,并且还需要访问每个帖子的附件,您可以这样做:

  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();
            }

【问题讨论】:

    标签: java android json gson


    【解决方案1】:

    这是一个可能应该被序列化为数组但没有被序列化的数据示例。解析它的一种解决方案是直接使用JSONObject。

    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
    

    数据可以也被视为一张地图,从 id 到附件。并且可以这样反序列化:

    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());
    

    这是真的

    【讨论】:

    • 我认为这里存在误解,无论是我还是你。这里表示的不是文章,而是文章的组成部分(即附件),我试图将它们反序列化为您之前帮助我处理的文章实例的字段。..
    • @drewmore4 - 确实如此。查看我的编辑(没什么实质性内容,基本上将Article 替换为Attachment)。
    • 这就是我的想法 :) 我正在尝试您的建议,但收到错误警告 - 只能遍历数组或 java.lang.Iterable 的实例 - 在 for 循环中。
    • @drewmore4 - 已编辑。您可能需要调整代码,我无法访问 IDE atm。
    • 谢谢。不得不做一些额外的工作,但你的解决方案让我到了那里。如果您好奇,请查看我的编辑
    【解决方案2】:

    首先从这个 JSONObject 创建 JSONArray。, 那么

    for(int i = 0; i < contacts.length(); i++){
                JSONObject c = contacts.getJSONObject(i);
    

    通过使用此循环获取字符串值并放入您想要的地图或对象并将其添加到 ArrayList

    HashMap<String, String> map = new HashMap<String, String>();
    
                // adding each child node to HashMap key => value
                map.put(TAG_ID, id);
    

    还有

    contactList.add(map);
    

    那么您可以使用该值。

    【讨论】:

      【解决方案3】:

      我该如何处理?我什至不知道该怎么称呼它 - 这里有多个“项目”,但它不是一个数组。

      看起来 JSON 中的集合非常适合 java.util.map。因此,我可能会将 JSON“附件”反序列化为 Map&lt;String, Atachment&gt;。然后,该映射很容易迭代,或者将附件值的集合转换为不同类型的集合,例如 List&lt;Attachment&gt; 或 Attachment[]。

      注意:The Gson User Guide 包含反序列化为通用集合的示例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-11
        • 2012-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多