我正在使用Gson解析某个API的JSON响应。
一切都运行正常,但现在似乎响应的一个字段可以以数组形式或单个元素形式出现,以便我得到com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
在这里,您可以看到导致问题的两个JSON版本的片段:
{
"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."
}
]
}
}
{
"Notes": {
"Note": {
"key": "medium",
"section": "low",
"priority": "1",
"message": "Life time for the battery will expire soon"
}
}
}
要解析 VERSION 1 ,我使用以下类:
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;
}
}
这适用于 VERSION 1 ,但当它发现JSON响应的一部分与 VERSION 2 匹配时,当然它会给出:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
如何对其进行反序列化Notes
,无论其格式如何?
答案 0 :(得分:4)
这个问题属于最着名的与Gson相关的问题组之一,我猜,并且设计不当的JSON响应受到了伤害。您可以在此处找到完全解决方案:Make GSON accept single objects where it expects arrays。拥有该类型的适配器工厂后,您可以注释这些映射:
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,你可以继续前进,只需删除内包装类。
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);
}
}
}
两者产生以下内容:
版本1.json
电池消耗突然升高 转换器上的电源可能太高 版本2.json
电池的使用寿命很快就会到期
答案 1 :(得分:0)
您遇到的问题是GSON期待一个数组,但JSON是对象的序列化。
基本上,GSON期待&#39; [&#39;但找到了&#39; {&#39;
因此,您应修改版本2的代码,以将JSON反序列化为单个Note对象。
此外,您应该查看两个JSON版本。
根据GSON,您的VERSION 2 JSON稍有效
您有一个Note对象列表
必须表示为
"Note"[ notes... ]
这正是版本1中的内容。
我建议将您的第2版JSON更改为类似的
"Notes"{
"Note":[
whatever note objects you have
go in here.
]
}
如果改变JSON不在您的权力范围内, 然后考虑为与此类似的案件开设另一个班级。
您应该使用@SerializedNames和Note对象创建新类,然后使用它来反序列化json。