为什么 Gson fromJson 会抛出 JsonSyntaxException: Expected BEGIN_OBJECT 但 was BEGIN_ARRAY? [英] Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?

查看:76
本文介绍了为什么 Gson fromJson 会抛出 JsonSyntaxException: Expected BEGIN_OBJECT 但 was BEGIN_ARRAY?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<小时>

我正在尝试使用 Gson#fromJson(String, Class).>

这段代码

import com.google.gson.Gson;公共类示例{公共静态无效主(字符串 [] args){String json = "{"nestedPojo":[{"name":null, "value":42}]}";Gson gson = new Gson();gson.fromJson(json, Pojo.class);}}类 Pojo {NestedPojonestedPojo;}类 NestedPojo {字符串名称;整数值;}

抛出以下异常

线程main"com.google.gson.JsonSyntaxException 中的异常:java.lang.IllegalStateException:预期为 BEGIN_OBJECT 但在第 1 行第 16 列路径 $.nestedPojo 处为 BEGIN_ARRAY在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200)在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103)在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196)在 com.google.gson.Gson.fromJson(Gson.java:810)在 com.google.gson.Gson.fromJson(Gson.java:775)在 com.google.gson.Gson.fromJson(Gson.java:724)在 com.google.gson.Gson.fromJson(Gson.java:696)在 com.example.Sample.main(Sample.java:23)引起:java.lang.IllegalStateException:预期为 BEGIN_OBJECT 但在第 1 行第 16 列路径 $.nestedPojo 处为 BEGIN_ARRAY在 com.google.gson.stream.JsonReader.beginObject(JsonReader.java:387)在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:189)……还有 7 个

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

解决方案

如异常消息所述

Caused by: java.lang.IllegalStateException: 预期为 BEGIN_OBJECT 但在第 1 行第 16 列路径 $.nestedPojo 处为 BEGIN_ARRAY

在反序列化时,Gson 期望得到一个 JSON 对象,但发现了一个 JSON 数组.由于它无法从一个转换到另一个,所以抛出了这个异常.

此处描述了 JSON 格式.简而言之,它定义了以下类型:对象、数组、字符串、数字、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":[{名称":空,价值":42}]}

在根部,这是一个 JSON 对象,其中包含一个名为 nestedPojo 的成员,它是一个 JSON 数组.该 JSON 数组包含一个元素,另一个具有两个成员的 JSON 对象.考虑到之前定义的映射,您希望这个 JSON 映射到一个 Java 对象,该对象具有一个名为 nestedPojo 的字段,属于某个 Collection 或数组类型,其中该类型定义了两个分别名为 namevalue 的字段.

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

NestedPojonestedPojo;

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

相反,您有 3 个选择:

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

    <代码>{nestedPojo":{名称":空,价值":42}}

  • 更改您的 Pojo 类型以期待 Collection 或数组类型

    List嵌套Pojo;//考虑更改名称并使用@SerializedNameNestedPojo[]nestedPojo;

  • 使用您自己的解析规则为 NestedPojo 编写和注册自定义反序列化器.例如

    class Custom 实现 JsonDeserializer{@覆盖public NestedPojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 抛出 JsonParseException {NestedPojonestedPojo = new NestedPojo();JsonArray jsonArray = json.getAsJsonArray();如果(jsonArray.size()!= 1){throw new IllegalStateException("意外的 json");}JsonObject jsonObject = jsonArray.get(0).getAsJsonObject();//只获取元素jsonElement jsonElement = jsonObject.get("name");如果 (!jsonElement.isJsonNull()) {NestedPojo.name = jsonElement.getAsString();}NestedPojo.value = jsonObject.get("value").getAsInt();返回nestedPojo;}}Gson gson = new GsonBuilder().registerTypeAdapter(NestedPojo.class, new Custom()).create();

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


I'm trying to deserialize some JSON content into a custom POJO type with 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$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

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

解决方案

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.

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

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 Number type; a JSON array maps to a Collection type or an array type; a JSON object maps to a Java Map type or, typically, a custom POJO type (not mentioned previously); null maps to Java's null, and the boolean values map to Java's true and false.

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.

In your case, you provided the following JSON

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

At the root, this is a JSON object which contains a member named nestedPojo which 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 nestedPojo of some Collection or array type, where that types defines two fields named name and value, respectively.

However, you've defined your Pojo type as having a field

NestedPojo nestedPojo;

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

Instead, you have 3 options:

  • Change your JSON to match the expected type

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

  • Change your Pojo type to expect a Collection or array type

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
    NestedPojo[] nestedPojo;
    

  • Write and register a custom deserializer for NestedPojo with 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();
    

这篇关于为什么 Gson fromJson 会抛出 JsonSyntaxException: Expected BEGIN_OBJECT 但 was BEGIN_ARRAY?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆