Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?
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 aCollection
or array typeList<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 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();
class Pojo {
NestedPojo nestedPojo;
}
in your json you have an array of nestedPojo so either you change the code
NestedPojo[] nestedPojo;
or you change the json string
String json = "{\"nestedPojo\":{\"name\":null, \"value\":42}}";