为什么Gson fromJson抛出一个JsonSyntaxException:期望某种types,但是是一些其他types?

(这篇文章是一个典型的问题 ,下面提供了一个示例答案。)


我试图反序列化一些JSON内容到Gson#fromJson(String, Class)的自定义POJOtypes。

这段代码

 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 

为什么不能正确地将我的JSON文本转换为我的POJOtypes?

正如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格式在这里描述。 简而言之,它定义了以下types:对象,数组,string,数字, null值以及布尔值truefalse

在Gson(和大多数JSONparsing器)中,存在以下映射:JSONstring映射到Java String ; 一个JSON数字映射到一个Java Numbertypes; 一个JSON数组映射到一个Collectiontypes或一个数组types; 一个JSON对象映射到一个Java Maptypes,或者通常是一个自定义的POJOtypes(前面没有提到); null映射到Java的null ,并且布尔值映射到Java的truefalse

Gson遍历您提供的JSON内容,并试图将其反序列化为您所请求的相应types。 如果内容不匹配或无法转换为预期的types,则会引发相应的exception。

在你的情况下,你提供了以下的JSON

 { "nestedPojo": [ { "name": null, "value": 42 } ] } 

在根目录下,这是一个JSON对象,它包含一个名为nestedPojo的成员,它是一个JSON数组。 那个JSON数组包含一个单独的元素,另一个有两个成员的JSON对象。 考虑到前面定义的映射,你会期望这个JSON映射到一个Java对象,它有一个名为nestedPojo的某个Collection或数组types的字段,其中这些types分别定义了名为namevalue两个字段。

但是,您已将Pojotypes定义为具有字段

 NestedPojo nestedPojo; 

既不是数组types也不是Collectiontypes。 Gson不能为这个字段反序列化相应的JSON。

相反,你有3个select:

  • 更改您的JSON以匹配预期的types

     { "nestedPojo": { "name": null, "value": 42 } } 
  • 更改您的Pojotypes以期望Collection或数组types

     List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName NestedPojo[] nestedPojo; 
  • 使用您自己的parsing规则为NestedPojo编写并注册一个自定义的反序列化器。 例如

     class Custom implements JsonDeserializer<NestedPojo> { @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; 

或者你改变jsonstring

 String json = "{\"nestedPojo\":{\"name\":null, \"value\":42}}";