Gson:反序列化可以是单个对象或数组的对象 [英] Gson: deserialize objects that can be a single object or an array

查看:122
本文介绍了Gson:反序列化可以是单个对象或数组的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Gson解析来自某个API的JSON响应. 一切正常,但是现在响应的字段之一似乎可以以数组形式或单个元素形式出现,所以我得到了com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:

I am using Gson to parse a JSON response from a certain API. Everything was working ok, but now seems like one of the fields of the response can come in an array form or in a single element form, so that I am getting com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:

在这里您可以看到导致问题的两个JSON版本的片段:

Here you can see the fragment of the two JSON versions causing problems:

{
    "Notes": {
        "Note": [
            {
                "key": "disruption-message",
                "section": "high",
                "priority": "1",
                "message": "The battery consumption raised suddenly."
            },
            {
                "key": "disruption-message",
                "section": "low",
                "priority": "2",
                "message": "The power on the converter might be too high."
            }
        ]
    }
}

版本2

{
    "Notes": {
        "Note": {
            "key": "medium",
            "section": "low",
            "priority": "1",
            "message": "Life time for the battery will expire soon"
        }
    }
}

要解析版本1 ,我正在使用以下类:

To parse the VERSION 1, I am using the following class:

public class Notes implements Serializable {

    @SerializedName("Note")
    @Expose
    private List<Note> note = null;

    public List<Note> getNote() {
        return note;
    }

    public void setNote(List<Note> note) {
        this.note = note;
    }

}

这与版本1 一起使用,但是当找到与版本2 匹配的JSON响应的一部分时,它会给出:

This works with the VERSION 1 but when it finds a part of the JSON response matching the VERSION 2, of course it gives:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT 

无论采用什么格式,如何使它反序列化Notes?

How can I make it deserialize Notes, whatever format they have?

推荐答案

我想,这个问题属于与Gson相关的最著名的问题组之一,设计不当的JSON响应会给人造成伤害.您可以在此处找到 exact 解决方案:

This question belongs to one of the most famous Gson-related question groups, I guess, and improperly designed JSON responses hurt. You can find the exact solution here: Make GSON accept single objects where it expects arrays . Once you have that type adapter factory, you can annotate your mappings like these:

final class ResponseV1 {

    @SerializedName("Notes")
    final NotesWrapperV1 notes = null;

}

final class NotesWrapperV1 {

    @SerializedName("Note")
    @JsonAdapter(AlwaysListTypeAdapterFactory.class)
    final List<Note> notes = null;

}

final class Note {

    final String key = null;
    final String section = null;
    final String priority = null;
    final String message = null;

}

IMO,您甚至可以继续进行操作,只需删除内部包装器类即可.

IMO, you can proceed even further and just remove the inner wrapper class.

final class ResponseV2 {

    @SerializedName("Notes")
    @JsonAdapter(NestedNotesTypeAdapterFactory.class)
    final List<Note> notes = null;

}

NestedNotesTypeAdapterFactory的实现方式如下:

final class NestedNotesTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeToken<List<Note>> noteListTypeToken = new TypeToken<List<Note>>() {
    };

    private NestedNotesTypeAdapterFactory() {
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        // Just add the factory method to AlwaysListTypeAdapterFactory and let it just return the class singleton (the factory is stateless, so it can be constructed once)
        final TypeAdapter<List<Note>> noteListTypeAdapter = getAlwaysListTypeAdapterFactory().create(gson, noteListTypeToken);
        final TypeAdapter<List<Note>> nestedNotesTypeAdapter = new NestedNotesTypeAdapter(noteListTypeAdapter);
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) nestedNotesTypeAdapter;
        return typeAdapter;
    }

    private static final class NestedNotesTypeAdapter
            extends TypeAdapter<List<Note>> {

        private final TypeAdapter<List<Note>> noteListTypeAdapter;

        private NestedNotesTypeAdapter(final TypeAdapter<List<Note>> noteListTypeAdapter) {
            this.noteListTypeAdapter = noteListTypeAdapter;
        }

        @Override
        public void write(final JsonWriter out, final List<Note> value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public List<Note> read(final JsonReader in)
                throws IOException {
            // "Unwrap" the Note property here
            in.beginObject();
            List<Note> notes = null;
            while ( in.hasNext() ) {
                final String name = in.nextName();
                switch ( name ) {
                case "Note":
                    // If we've reached the Note property -- just read the list
                    notes = noteListTypeAdapter.read(in);
                    break;
                default:
                    throw new MalformedJsonException("Unrecognized " + name + " at " + in);
                }
            }
            in.endObject();
            return notes;
        }

    }
}

两种实现的测试用例:

for ( final String resource : ImmutableList.of("version-1.json", "version-2.json") ) {
    System.out.println(resource);
    try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43868120.class, resource) ) {
        final ResponseV1 response = gson.fromJson(jsonReader, ResponseV1.class);
        for ( final Note note : response.notes.notes ) {
            System.out.println(note.message);
        }
    }
}

for ( final String resource : ImmutableList.of("version-1.json", "version-2.json") ) {
    System.out.println(resource);
    try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43868120.class, resource) ) {
        final ResponseV2 response = gson.fromJson(jsonReader, ResponseV2.class);
        for ( final Note note : response.notes ) {
            System.out.println(note.message);
        }
    }
}

两者都会产生以下内容:

Both produce the following:

version-1.json
电池电量突然增加.
转换器上的功率可能太高.
版本2.json
电池的使用寿命即将到期

version-1.json
The battery consumption raised suddenly.
The power on the converter might be too high.
version-2.json
Life time for the battery will expire soon

这篇关于Gson:反序列化可以是单个对象或数组的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆