为什么Gson fromJson抛出一个JsonSyntaxException:预期BEGIN_OBJECT但是BEGIN_ARRAY?
(这篇文章是一个规范性的问题 ,下面提供了一个示例答案。)
我正在尝试使用Gson#fromJson(String, Class)
将一些JSON内容反序列化为自定义POJO类型。
这段代码
import com.google.gson.Gson; public class Sample { public static void main(String[] args) { String json = "{\"nestedPojo\":[{\"name\":null, \"value\":42}]}"; Gson gson = new Gson(); gson.fromJson(json, Pojo.class); } } class Pojo { NestedPojo nestedPojo; } class NestedPojo { String name; int value; }
抛出以下exception
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196) at com.google.gson.Gson.fromJson(Gson.java:810) at com.google.gson.Gson.fromJson(Gson.java:775) at com.google.gson.Gson.fromJson(Gson.java:724) at com.google.gson.Gson.fromJson(Gson.java:696) at com.example.Sample.main(Sample.java:23) Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:387) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:189) ... 7 more
为什么Gson不能正确地将我的JSON文本转换为我的POJO类型?
正如exception消息所述
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo
反序列化时,Gson期待一个JSON对象,但找到了一个JSON数组。 由于它无法从一个转换为另一个,它抛出了这个exception。
这里描述了 JSON格式。 简而言之,它定义了以下类型:对象,数组,字符串,数字, null
,以及布尔值true
和false
。
在Gson(和大多数JSON解析器)中,存在以下映射:JSON字符串映射到Java String
; JSON号映射到Java Number
类型; JSON数组映射到Collection
类型或数组类型; JSON对象映射到Java Map
类型,或者通常是自定义POJO类型(之前未提及); null
映射到Java的null
,布尔值映射到Java的true
和false
。
Gson迭代您提供的JSON内容,并尝试将其反序列化为您请求的相应类型。 如果内容不匹配或无法转换为预期类型,则会抛出相应的exception。
在您的情况下,您提供了以下JSON
{ "nestedPojo": [ { "name": null, "value": 42 } ] }
在根目录下,这是一个JSON对象,其中包含一个名为nestedPojo
的成员,该成员是一个JSON数组。 该JSON数组包含单个元素,另一个JSON对象包含两个成员。 考虑到之前定义的映射,您希望此JSON映射到Java对象,该对象具有名为nestedPojo
的某个Collection
或数组类型的字段,其中该类型分别定义名为name
和value
两个字段。
但是,您已将Pojo
类型定义为具有字段
NestedPojo nestedPojo;
既不是数组类型也不是Collection
类型。 Gson无法反序列化此字段的相应JSON。
相反,您有3个选择:
-
更改您的JSON以匹配预期的类型
{ "nestedPojo": { "name": null, "value": 42 } }
-
将
Pojo
类型更改为期望Collection
或数组类型List
nestedPojo; // consider changing the name and using @SerializedName NestedPojo[] nestedPojo; -
使用您自己的解析规则为
NestedPojo
编写和注册自定义反序列化NestedPojo
。 例如class Custom implements JsonDeserializer
{ @Override public NestedPojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { NestedPojo nestedPojo = new NestedPojo(); JsonArray jsonArray = json.getAsJsonArray(); if (jsonArray.size() != 1) { throw new IllegalStateException("unexpected json"); } JsonObject jsonObject = jsonArray.get(0).getAsJsonObject(); // get only element JsonElement jsonElement = jsonObject.get("name"); if (!jsonElement.isJsonNull()) { nestedPojo.name = jsonElement.getAsString(); } nestedPojo.value = jsonObject.get("value").getAsInt(); return nestedPojo; } } Gson gson = new GsonBuilder().registerTypeAdapter(NestedPojo.class, new Custom()).create();
class Pojo { NestedPojo nestedPojo; }
在你的json中你有一个nestedPojo数组,所以你要么改变代码
NestedPojo[] nestedPojo;
或者你改变了json字符串
String json = "{\"nestedPojo\":{\"name\":null, \"value\":42}}";