猿问

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

在 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]

我该如何处理这些字符串数组的情况?


湖上湖
浏览 220回答 3
3回答

子衿沉夜

如果在某些情况下相同的端点返回不同的类型,我建议将该部分包装在一个对象中并使用反序列化器检查类型并相应地分配。你可以这样做:public Parent serialize(String jsonString) {&nbsp; &nbsp; GsonBuilder builder = new GsonBuilder();&nbsp; &nbsp; builder.registerTypeAdapter(WrappedChild.class, new ChildDeserializer());&nbsp; &nbsp; Gson gson = builder.create();&nbsp; &nbsp; return gson.fromJson(jsonString, Parent.class);}class Parent {&nbsp; &nbsp; public List<WrappedChild> children;}class ObjectChild {&nbsp; &nbsp; public String body;}class WrappedChild {&nbsp; &nbsp; public ObjectChild objectChild;&nbsp; &nbsp; public String stringChild;}class ChildDeserializer implements JsonDeserializer<WrappedChild> {&nbsp; &nbsp; private Gson gson = new Gson();&nbsp; &nbsp; @Override&nbsp; &nbsp; public WrappedChild deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {&nbsp; &nbsp; &nbsp; &nbsp; if (json != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (json.isJsonObject()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WrappedChild result = new WrappedChild();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.objectChild = gson.fromJson(json, ObjectChild.class);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (json.isJsonPrimitive()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WrappedChild result = new WrappedChild();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.stringChild = json.getAsString();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return null; // Or throw new Exception("Unknown child type");&nbsp; &nbsp; }}如果您正在使用改造,只需GsonConverterFactory.create在创建服务时将构建器创建的 Gson作为参数传递给。

收到一只叮咚

您应该仔细研究Emre Eran 的答案,因为这样您就可以完全控制反序列化。我将给出另一种方法,在某些情况下可能需要较少的努力。它基于Gson反序列化的“基本智能” 。如果您声明包含以下内容的children类:public class Parent {&nbsp; &nbsp; Collection<?> children;}Gson尽量“猜测”对象类型。如果它面对一个简单的字符串,它将被反序列化为String. 如果它像第一个Json示例中那样面对数据,它将反序列化为树的com.google.gson.internal.LinkedTreeMap一个Java版本Json。因此,根据data第一个示例中对象的复杂程度以及您总体上如何使用结果,您可能不需要编写自定义反序列化器(无论如何最终可能是更好的解决方案)。

慕的地8271018

对不起,迟到的答案,感谢您带领我走向正确的方向 Emre!我最终让 GsonBuilder 使用自定义方法 getGsonAdaptedData。在后台线程中检索 JSON 响应后:...Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, (JsonDeserializer<Data>) (arg0, arg1, arg2) -> {&nbsp; &nbsp; &nbsp; &nbsp; JsonObject dataJsonObject = arg0.getAsJsonObject();&nbsp; &nbsp; &nbsp; &nbsp; Data data = new Gson().fromJson(dataJsonObject, Data.class);&nbsp; &nbsp; &nbsp; &nbsp; return RedditUtils.getGsonAdaptedData(dataJsonObject.get("children").getAsJsonArray(), data);&nbsp; &nbsp; }).create();&nbsp; &nbsp; 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 Datapublic static Data getGsonAdaptedData(JsonArray childrenJsonArray, Data data) {&nbsp; &nbsp; if (childrenJsonArray.size() > 0) {&nbsp; &nbsp; &nbsp; &nbsp; Gson gson = new Gson();&nbsp; &nbsp; &nbsp; &nbsp; if (childrenJsonArray.get(0).isJsonObject()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.setChildrenList(gson.fromJson(childrenJsonArray,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new TypeToken<List<Children>>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }.getType()));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Loops through every Data object in the array looking for children and replies&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < childrenJsonArray.size(); i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JsonObject nestedDataJsonObject = childrenJsonArray.get(i).getAsJsonObject().get("data").getAsJsonObject();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (nestedDataJsonObject.has("children")) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getGsonAdaptedData(nestedDataJsonObject.get("children").getAsJsonArray(), data.getChildren().get(i).getData());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (nestedDataJsonObject.has("replies") && nestedDataJsonObject.get("replies").isJsonObject()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.getChildren().get(i).getData().setRepliesObject(gson.fromJson(nestedDataJsonObject.get("replies"),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new TypeToken<Replies>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }.getType()));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getGsonAdaptedData(nestedDataJsonObject.get("replies").getAsJsonObject().get("data").getAsJsonObject().get("children").getAsJsonArray(), data.getChildren().get(i).getData());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.setRepliesList(gson.fromJson(childrenJsonArray,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new TypeToken<List<String>>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }.getType()));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return data;}
随时随地看视频慕课网APP

相关分类

Java
我要回答