首页 文章

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

提问于
浏览
8

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


我正在尝试使用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 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 回答

  • 7

    正如异常消息所述

    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 或数组类型,其中该类型分别定义了两个名为 namevalue 的字段 .

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

    NestedPojo nestedPojo;
    

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

    相反,您有3个选择:

    • 更改您的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();
    
  • 27
    class Pojo {
      NestedPojo nestedPojo;
    }
    

    在你的json中你有一个nestedPojo数组,所以你要么改变代码

    NestedPojo[] nestedPojo;
    

    或者你改变了json字符串

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

相关问题