当前位置: 首页 > 知识库问答 >
问题:

改装:如何解析结合了数组和对象的JSON数组?

乐正宏深
2023-03-14

我正在开发一个Android应用程序,它使用改进的OkHttp连接到REST API并使用JSON数据。我对改装还比较陌生,所以我还在学习它是如何工作的,但到目前为止,它还是相当顺利的。然而,我遇到了一个不寻常的问题。

其中一个endpoint返回的数据有点像这样:

{
    "success": true,
    "data": [
        [
            {
                "field": "value1",
                ...
            },
            {
                "field": "value2",
                ...
            },
            ...
        ],
        {
           "info": "value",
           "info2": "value",
           "info3": "value",
        }
    ],
    "message": "This is the message."
}

在大多数情况下,这是一个相当标准的JSON响应。我们有一个“状态”值、一个“消息”和一个包含正在返回的重要数据的“数据”值。但是,“数据”的结构有一个问题。如您所见,它是一个数组,但它不仅仅是一个对象数组。它的第一个元素是值数组,它的第二个元素是一个对象。

格森不喜欢这样。如果我想创建一个POJO来使用Gson将其解析为,我希望执行如下操作:

public class JsonResponse {

    @SerializedName("success")
    @Expose
    boolean success;

    @SerializedName("message")
    @Expose
    String message;

    @SerializedName("data")
    @Expose
    private ArrayList<MyObject> data = new ArrayList<>();

    public ArrayList<MyObject> getData() {
        return data;
    }

    public void setData(ArrayList<MyObject> data) {
        this.data = data;
    }
}

其中“MyObject”是这样的包裹:

public class MyObject implements Parcelable {
      @SerializedName("field")
      @Expose
      boolean field;

      ...
}

但这不起作用,因为“数据”不仅仅是一个对象数组;它是一个包含对象数组和另一个顶级对象的数组。

我可以将“data”定义为“Array”,它似乎可以解析值。但后来它们变成了通用的LinkedTreeMap对象,所以我失去了Gson的JSON的优势-

在Retrofit/Gson中是否有一种优雅的方法来处理这样的混合数组?我不对来自API的数据负责,所以我不认为改变它是一种选择。

共有2个答案

周伟泽
2023-03-14

您似乎没有使用列表

例如<代码>JsonResponse比jsonschema2pojo生成的更简单:

final class JsonResponse {

    final boolean success = Boolean.valueOf(false);
    final String message = null;
    final List<MyObject> data = null;

}

现在,MyObject可以如下所示:

abstract class MyObject
        implements Parcelable {

    private MyObject() {
    }

    static <E> MyObject multiple(final List<E> list) {
        return new MultipleObjects<>(list);
    }

    static final class SingleObject
            extends MyObject {

        private SingleObject() {
        }

        final String info = null;
        final String info2 = null;
        final String info3 = null;

    }

    static final class MultipleObjects<E>
            extends MyObject
            implements List<E> {

        private final List<E> list;

        private MultipleObjects(final List<E> list) {
            this.list = list;
        }

        // @formatter:off
        @Override public int size() { return list.size(); }
        @Override public boolean isEmpty() { return list.isEmpty(); }
        @Override public boolean contains(final Object o) { return list.contains(o); }
        @Override public Iterator<E> iterator() { return list.iterator(); }
        @Override public Object[] toArray() { return list.toArray(); }
        @Override public <T> T[] toArray(final T[] a) { return list.toArray(a); }
        @Override public boolean add(final E e) { return list.add(e); }
        @Override public boolean remove(final Object o) { return list.remove(o); }
        @Override public boolean containsAll(final Collection<?> c) { return list.containsAll(c); }
        @Override public boolean addAll(final Collection<? extends E> c) { return list.addAll(c); }
        @Override public boolean addAll(final int index, final Collection<? extends E> c) { return list.addAll(index, c); }
        @Override public boolean removeAll(final Collection<?> c) { return list.removeAll(c); }
        @Override public boolean retainAll(final Collection<?> c) { return list.retainAll(c); }
        @Override public void clear() { list.clear(); }
        @Override public E get(final int index) { return list.get(index); }
        @Override public E set(final int index, final E element) { return list.set(index, element); }
        @Override public void add(final int index, final E element) { list.add(index, element); }
        @Override public E remove(final int index) { return list.remove(index); }
        @Override public int indexOf(final Object o) { return list.indexOf(o); }
        @Override public int lastIndexOf(final Object o) { return list.lastIndexOf(o); }
        @Override public ListIterator<E> listIterator() { return list.listIterator(); }
        @Override public ListIterator<E> listIterator(final int index) { return list.listIterator(index); }
        @Override public List<E> subList(final int fromIndex, final int toIndex) { return list.subList(fromIndex, toIndex); }
        // @formatter:on

    }

}

上面的类实现了一个可以通过两种方式实现的抽象类。请注意,设计中没有公开公共构造函数SingleObject可以使用Gson非常容易地使用反射策略进行反序列化,而MultipleObject是一个类似数组的对象,需要一些手动构造。

反序列化部分:

final class MyObjectJsonDeserializer
        implements JsonDeserializer<MyObject> {

    private static final JsonDeserializer<MyObject> myObjectJsonDeserializer = new MyObjectJsonDeserializer();

    // You have to detect it more accurately yourself   
    private static final Type genericListType = new TypeToken<List<Object>>() {
    }.getType();

    private MyObjectJsonDeserializer() {
    }

    static JsonDeserializer<MyObject> getMyObjectJsonDeserializer() {
        return myObjectJsonDeserializer;
    }

    @Override
    public MyObject deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
            throws JsonParseException {
        if ( jsonElement.isJsonNull() ) {
            return null;
        }
        if ( jsonElement.isJsonObject() ) {
            // Note that the deserialization is implemented using context,
            // because it makes sure that you are using the Gson instance configuration
            // Simply speaking: do not create gson instances in 99,9% cases
            return context.deserialize(jsonElement, MyObject.SingleObject.class);
        }
        if ( jsonElement.isJsonArray() ) {
            return multiple(context.deserialize(jsonElement, genericListType));
        }
        // Or create a more sophisticated detector... Or redesign your mappigns
        if ( jsonElement.isJsonPrimitive() ) {
            throw new JsonParseException("Cannot parse primitives");
        }
        throw new AssertionError(jsonElement);
    }

}

示例使用:

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(MyObject.class, getMyObjectJsonDeserializer())
        .create();

public static void main(final String... args)
        throws IOException {
    try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43946453.class, "polymorphic.json") ) {
        final JsonResponse response = gson.fromJson(jsonReader, JsonResponse.class);
        for ( final MyObject datum : response.data ) {
            System.out.println(datum.getClass().getSimpleName());
        }
    }
}

输出:

多个对象单个对象

上官凯泽
2023-03-14

有一种方法。

添加一个自定义JsonDeserializer并手动处理该字段。

示例

public static class Deserializer implements JsonDeserializer<JsonResponse> {

    private final Gson gson = new GsonBuilder().create();

    @Override
    public JsonResponse deserialize(JsonElement json, Type typeOfT,
                                      JsonDeserializationContext context)
            throws JsonParseException {
        JsonResponse response = gson.fromJson(json, typeOfT);

        JsonObject jObject = json.getAsJsonObject();
        //Handle jObject here, and parse each object of data array 
        //accordingly to its type - JsonObject/JsonArray
        return response;
    }
}

您需要在全局Gson实例中注册它,如下所示:

new GsonBuilder()
            .registerTypeAdapter(JsonResponse.class, new JsonResponse.Deserializer())
            .create();
 类似资料:
  • 问题内容: 我试图从JSON数组中获取每个JSON对象。我通过HTTP发布获得此数据。 我知道我的数据是什么样的: 我的示例代码和结构如下所示: 我不确定如何遍历JSON数组并获取JSON对象,然后仅使用JSON对象。 问题答案: 试试这个作为您的结构, 您的名称不正确,顶层名称也不正确。解码为a之后,您可以遍历切片以获取每个切片

  • 问题内容: 我有以下格式的对象数组: 我想要得到的是C#中的代码,其中一个对象包含一个json对象中的所有数据。问题是,我可以 不 使一个类与此对象喜欢这里的属性: 因为我每次都会得到不同的结果,但是我知道它总是一个对象数组。有人知道我如何设法取回一系列对象? 编辑 我必须通过将该对象传递给powershell 。因此,输出仅应是中的对象。 问题答案: 像这样使用newtonsoft:

  • 问题内容: JSON如下所示: 我正在尝试使用Android中的以下Java代码来解析它: JSONObject jObj = null; 尝试{jObj = new JSONObject(jsonStr); 我没有得到任何结果。如何成功解析此JSON?我正在使用Android Studio。 另外,如果阵列中有多个零件,我们如何确保将每个零件都打印出来? 问题答案: 您的JSON字符串以JSON

  • 问题内容: 我很难找到一种方法来解析JSONArray。看起来像这样: 如果JSON的写法不同,我知道如何解析它(换句话说,如果我返回了json对象而不是对象数组)。但这就是我所必须拥有的。 *编辑:这是一个有效的json。我使用此json制作了一个iPhone应用,现在我需要在Android上使用它,但无法弄清楚。有很多示例,但是它们都是与JSONObject相关的。我需要JSONArray。

  • 问题内容: 我想知道如何解析NodeJS中的JSON对象数组? 我想将JSON数组发布到服务器,并能够将接收到的数组用作可靠的JavaScript数组。 提前致谢。 这是我要使用stringify函数将Array转换为String的前端部分 这是我尝试将JSON对象的Array转换为Array的后端部分 这是我要发送到服务器的数组: 这是源代码 问题答案: 在您的: 然后,您可以使用来获取过帐的值

  • 我很难找到解析JSONArray的方法。看起来是这样的: 如果JSON的编写方式不同(换句话说,如果返回的是JSON对象而不是对象数组),我知道如何解析它。但这是我所拥有的一切,我必须要去做。 *编辑:这是一个有效的json。我用这个json做了一个iPhone的应用程序,现在我需要为Android做,但无法解决这个问题。外面有很多例子,但它们都是与JSONObject相关的。我需要一些用于JSO