Why does Gson from Json throw JsonSyntaxException: BEGIN_OBJECT expected, but there was BEGIN_ARRAY?
(This post should be a canonical question with a sample answer provided below.)
I am trying to deserialize 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 following 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 Gso convert the JSON text to my POJO type correctly?
source to share
As stated in the error message
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo
when deserializing, Gson was expecting a JSON object but found a JSON array. Since he could not convert from one to the other, he threw this exception.
The JSON format is described here . In short, it defines the following types: objects, arrays, strings, numbers, null
and booleans true
and false
.
Gson (and most JSON parsers) have the following mappings: JSON string maps to Java String
; JSON number maps to Java type Number
; a JSON array is mapped to an array type Collection
or type; the JSON object maps to a Java type, Map
or generally a custom POJO type (not previously mentioned); null
maps to Java null
, and booleans maps to Java true
and false
.
Gson iterates through the JSON content you provide and tries to deserialize it to the appropriate type you requested. If the content does not match or cannot be converted to the expected type, it will throw a corresponding exception.
In your case, you provided the following JSON
{
"nestedPojo": [
{
"name": null,
"value": 42
}
]
}
At the root, it is a JSON object that contains a named member nestedPojo
, which is a JSON array. This JSON array contains one element, another JSON object with two members. Given the mappings defined earlier, you would expect this JSON to represent a Java object that has a field named nestedPojo
some Collection
or array type, where those types define two fields named name
and value
, respectively.
However, you have defined the type Pojo
as having a field
NestedPojo nestedPojo;
which is not an array type, not a type Collection
. Gson cannot deserialize the corresponding JSON for this field.
Instead, you have 3 options:
-
Modify your JSON to match the expected type
{ "nestedPojo": { "name": null, "value": 42 } }
-
Change type
Pojo
to expectCollection
or array typeList<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName NestedPojo[] nestedPojo;
-
Write and register your own deserializer for
nestedPojo
using your own parsing rules. for exampleclass 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();
source to share