为了账号安全,请及时绑定邮箱和手机立即绑定

GSON - 如何解析两个名称相同但参数不同的 JSONArray?

GSON - 如何解析两个名称相同但参数不同的 JSONArray?

湖上湖 2021-10-28 16:49:56
在 Reddit JSON API 中,评论可以包含两种不同类型的 JSONArray,都称为“子级”。“children”通常是一个包含字符串“kind”和对象“data”的对象数组:"children": [ { "kind": "t3", "data": {} } ...]我一直很好地处理这些。我的问题是,有时,孩子将是一个简单的字符串数组:"children": [ "e78i3mq", "e78hees", "e78jq6q" ]解析这些时,GSON 会抛出如下异常:引起:java.lang.IllegalStateException:预期为 BEGIN_OBJECT,但在第 1 行第 3780 列路径 $[1].data.children[0].data.reply.data.children[0].data.reply.data.children 处为 STRING [0].data.reply.data.children[0].data.children[0]我该如何处理这些字符串数组的情况?
查看完整描述

3 回答

?
子衿沉夜

TA贡献1828条经验 获得超3个赞

如果在某些情况下相同的端点返回不同的类型,我建议将该部分包装在一个对象中并使用反序列化器检查类型并相应地分配。你可以这样做:


public Parent serialize(String jsonString) {

    GsonBuilder builder = new GsonBuilder();

    builder.registerTypeAdapter(WrappedChild.class, new ChildDeserializer());

    Gson gson = builder.create();

    return gson.fromJson(jsonString, Parent.class);

}


class Parent {

    public List<WrappedChild> children;

}


class ObjectChild {

    public String body;

}


class WrappedChild {

    public ObjectChild objectChild;

    public String stringChild;

}


class ChildDeserializer implements JsonDeserializer<WrappedChild> {

    private Gson gson = new Gson();


    @Override

    public WrappedChild deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        if (json != null) {

            if (json.isJsonObject()) {

                WrappedChild result = new WrappedChild();

                result.objectChild = gson.fromJson(json, ObjectChild.class);

                return result;

            } else if (json.isJsonPrimitive()) {

                WrappedChild result = new WrappedChild();

                result.stringChild = json.getAsString();

                return result;

            }

        }

        return null; // Or throw new Exception("Unknown child type");

    }

}

如果您正在使用改造,只需GsonConverterFactory.create在创建服务时将构建器创建的 Gson作为参数传递给。


查看完整回答
反对 回复 2021-10-28
?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

您应该仔细研究Emre Eran 的答案,因为这样您就可以完全控制反序列化。我将给出另一种方法,在某些情况下可能需要较少的努力。它基于Gson反序列化的“基本智能” 。


如果您声明包含以下内容的children类:


public class Parent {

    Collection<?> children;

}

Gson尽量“猜测”对象类型。如果它面对一个简单的字符串,它将被反序列化为String. 如果它像第一个Json示例中那样面对数据,它将反序列化为树的com.google.gson.internal.LinkedTreeMap一个Java版本Json。


因此,根据data第一个示例中对象的复杂程度以及您总体上如何使用结果,您可能不需要编写自定义反序列化器(无论如何最终可能是更好的解决方案)。


查看完整回答
反对 回复 2021-10-28
?
慕的地8271018

TA贡献1796条经验 获得超4个赞

对不起,迟到的答案,感谢您带领我走向正确的方向 Emre!


我最终让 GsonBuilder 使用自定义方法 getGsonAdaptedData。


在后台线程中检索 JSON 响应后:


...

Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, (JsonDeserializer<Data>) (arg0, arg1, arg2) -> {

        JsonObject dataJsonObject = arg0.getAsJsonObject();

        Data data = new Gson().fromJson(dataJsonObject, Data.class);

        return RedditUtils.getGsonAdaptedData(dataJsonObject.get("children").getAsJsonArray(), data);

    }).create();

    final Feed responseSubredditFeed = gson.fromJson(jsonString, Feed.class);

...

RedditUtils.getGsonAdaptedData


// JSON returned for Reddit comments can contain two types of arrays named "children"

// This method checks to see if we were given a Children array or String array

// JSON member "replies" is similar, and can be found in the Data of some Children

// If the method finds a nested "children" array, it recursively adapts its Data

public static Data getGsonAdaptedData(JsonArray childrenJsonArray, Data data) {


    if (childrenJsonArray.size() > 0) {


        Gson gson = new Gson();


        if (childrenJsonArray.get(0).isJsonObject()) {


            data.setChildrenList(gson.fromJson(childrenJsonArray,

                    new TypeToken<List<Children>>() {

                    }.getType()));


            // Loops through every Data object in the array looking for children and replies

            for (int i = 0; i < childrenJsonArray.size(); i++) {


                JsonObject nestedDataJsonObject = childrenJsonArray.get(i).getAsJsonObject().get("data").getAsJsonObject();


                if (nestedDataJsonObject.has("children")) {

                    getGsonAdaptedData(nestedDataJsonObject.get("children").getAsJsonArray(), data.getChildren().get(i).getData());


                } else if (nestedDataJsonObject.has("replies") && nestedDataJsonObject.get("replies").isJsonObject()) {


                    data.getChildren().get(i).getData().setRepliesObject(gson.fromJson(nestedDataJsonObject.get("replies"),

                            new TypeToken<Replies>() {

                            }.getType()));


                    getGsonAdaptedData(nestedDataJsonObject.get("replies").getAsJsonObject().get("data").getAsJsonObject().get("children").getAsJsonArray(), data.getChildren().get(i).getData());

                }

            }

        } else {


            data.setRepliesList(gson.fromJson(childrenJsonArray,

                    new TypeToken<List<String>>() {

                    }.getType()));

        }

    }


    return data;

}


查看完整回答
反对 回复 2021-10-28
  • 3 回答
  • 0 关注
  • 213 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信