我正在使用 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,但是当它找到与 VERSION 2 匹配的 JSON 响应的一部分时,它当然会给出:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
我怎样才能让它反序列化
Notes
,无论它们有什么格式?
我猜这个问题属于最著名的 Gson 相关问题组之一,设计不当的 JSON 响应会造成伤害。您可以在这里找到精确解决方案:使 GSON 接受需要数组的单个对象。一旦您拥有该类型的适配器工厂,您就可以像这样注释您的映射:
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
电池的使用寿命即将到期
您遇到的问题是 GSON 需要一个数组,但 JSON 是对象的序列化。
基本上,GSON 期望 '[' 但发现 '{'
因此,您应该修改 version2 的代码,将 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。
我找到了一个快速排序的解决方案,方法是在模型类中使用参数作为
Any
,然后将其序列化。
private fun serializableToList(obj: Any): List<Pojo> {
val pojoList: MutableList<Pojo> = mutableListOf()
when (obj) {
is List<*> -> {
obj.forEach {
val pojoObject = Gson().fromJson(Gson().toJson(it), Pojo::class.java)
pojoList.add(pojoObject)
}
}
else -> {
val pojoObject = Gson().fromJson(Gson().toJson(obj), Pojo::class.java)
pojoList.add(pojoObject)
}
}
return pojoList
}