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?

+8


source to share


2 answers


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 expect Collection

    or array type

    List<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 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();
    
          

+27


source


class Pojo {
  NestedPojo nestedPojo;
}

      

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

  NestedPojo[] nestedPojo;

      



or you change the json string

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

      

+7


source







All Articles