Java 为什么 Gson fromJson 会抛出一个 JsonSyntaxException: Expected BEGIN_OBJECT 但 was BEGIN_ARRAY?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33621808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:50:09  来源:igfitidea点击:

Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?

javajsongson

提问by Sotirios Delimanolis

(This post is meant to be a canonical questionwith a sample answer provided below.)

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



I'm trying to deserialize some JSON content into a custom POJO type with Gson#fromJson(String, Class).

我正在尝试将一些 JSON 内容反序列化为带有Gson#fromJson(String, Class).

This piece of code

这段代码

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;
}

throws the follow 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.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

Why can't Gson properly convert my JSON text to my POJO type?

为什么 Gson 不能正确地将我的 JSON 文本转换为我的 POJO 类型?

采纳答案by Sotirios Delimanolis

As the exception message states

正如异常消息所述

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

while deserializing, Gson was expecting a JSON object, but found a JSON array. Since it couldn't convert from one to the other, it threw this exception.

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

The JSON format is described here. In short, it defines the following types: objects, arrays, strings, numbers, null, and the boolean values trueand false.

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

In Gson (and most JSON parsers), the following mappings exist: a JSON string maps to a Java String; a JSON number maps to a Java Numbertype; a JSON array maps to a Collectiontype or an array type; a JSON object maps to a Java Maptype or, typically, a custom POJOtype (not mentioned previously); nullmaps to Java's null, and the boolean values map to Java's trueand false.

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

Gson iterates through the JSON content that you provide and tries to deserialize it to the corresponding type you've requested. If the content doesn't match or can't be converted to the expected type, it'll throw a corresponding exception.

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

In your case, you provided the following JSON

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

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

At the root, this is a JSON object which contains a member named nestedPojowhich is a JSON array. That JSON array contains a single element, another JSON object with two members. Considering the mappings defined earlier, you'd expect this JSON to map to a Java object which has a field named nestedPojoof some Collectionor array type, where that types defines two fields named nameand value, respectively.

在根上,这是一个 JSON 对象,其中包含一个名为nestedPojoJSON 数组的成员。该 JSON 数组包含一个元素,另一个具有两个成员的 JSON 对象。考虑到之前定义的映射,您希望这个 JSON 映射到一个 Java 对象,该对象具有一个名为nestedPojosomeCollection或数组类型的字段,其中该类型分别定义了两个名为name和 的字段value

However, you've defined your Pojotype as having a field

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

NestedPojo nestedPojo;

that is neither an array type, nor a Collectiontype. Gson can't deserialize the corresponding JSON for this field.

那既不是数组类型,也不是Collection类型。Gson 无法反序列化该字段对应的 JSON。

Instead, you have 3 options:

相反,您有 3 个选择:

  • Change your JSON to match the expected type

    {
        "nestedPojo": {
            "name": null,
            "value": 42
        }
    }
    
  • Change your Pojotype to expect a Collectionor array type

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
    NestedPojo[] nestedPojo;
    
  • Write and register a custom deserializer for NestedPojowith your own parsing rules. For example

    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();
    
  • 更改您的 JSON 以匹配预期类型

    {
        "nestedPojo": {
            "name": null,
            "value": 42
        }
    }
    
  • 更改您的Pojo类型以期望一个Collection或数组类型

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
    NestedPojo[] nestedPojo;
    
  • 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();
    

回答by Tahar Bakir

class Pojo {
  NestedPojo nestedPojo;
}

in your json you have an array of nestedPojo so either you change the code

在您的 json 中,您有一个 nestedPojo 数组,因此您可以更改代码

  NestedPojo[] nestedPojo;

or you change the json string

或者你改变json字符串

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