为什么Gson fromJson抛出一个JsonSyntaxException:预期BEGIN_OBJECT但是BEGIN_ARRAY?

时间:2015-11-10 02:21:45

标签: java json gson

(这篇文章的意思是canonical question,下面提供了一个示例答案。)

我尝试将某些JSON内容反序列化为Gson#fromJson(String, Class)的自定义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 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类型?

2 个答案:

答案 0 :(得分:29)

正如异常消息所述

Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo

在反序列化时,Gson期待一个JSON对象,但找到了一个JSON数组。由于它无法从一个转换为另一个,因此它抛出了这个异常。

JSON格式描述为here。简而言之,它定义了以下类型:对象,数组,字符串,数字,null以及布尔值truefalse

在Gson(和大多数JSON解析器)中,存在以下映射:JSON字符串映射到Java String; JSON编号映射到Java Number类型; JSON数组映射到Collection类型或数组类型; JSON对象映射到Java Map类型,或者通常是自定义POJO类型(之前未提及); null映射到Java的null,布尔值映射到Java的truefalse

Gson迭代您提供的JSON内容,并尝试将其反序列化为您已请求的相应类型。如果内容不匹配或无法转换为预期类型,则会引发相应的异常。

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

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

在根目录下,这是一个JSON对象,其中包含一个名为nestedPojo的成员,它是一个JSON数组。该JSON数组包含单个元素,另一个JSON对象包含两个成员。考虑到前面定义的映射,您希望此JSON映射到Java对象,该对象具有名为nestedPojo的某个Collection或数组类型的字段,其中该类型定义了两个名为{{的字段分别为1}}和name

但是,您已将value类型定义为具有字段

Pojo

既不是数组类型,也不是NestedPojo nestedPojo; 类型。 Gson无法对此字段的相应JSON进行反序列化。

相反,您有3个选项:

  • 更改您的JSON以匹配预期的类型

    Collection
  • { "nestedPojo": { "name": null, "value": 42 } } 类型更改为Pojo或数组类型

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

    NestedPojo

答案 1 :(得分:7)

class Pojo {
  NestedPojo nestedPojo;
}
在你的json中,你有一个nestedPojo数组 所以你要么改变代码

  NestedPojo[] nestedPojo;

或者你改变了json字符串

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