¿Por qué Gson fromJson arroja una excepción JsonSyntaxException: se esperaba BEGIN_OBJECT pero era BEGIN_ARRAY?

4 minutos de lectura

¿Por que Gson fromJson arroja una excepcion JsonSyntaxException se esperaba
Sotirios Delimanolis

(Esta publicación pretende ser una pregunta canónica con una respuesta de muestra a continuación).


Estoy tratando de deserializar algún contenido JSON en un tipo POJO personalizado con Gson#fromJson(String, Class).

Este pedazo de código

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;
}

lanza la excepción de seguimiento

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

¿Por qué Gson no puede convertir correctamente mi texto JSON a mi tipo POJO?

  • Podría valer la pena agregar una segunda respuesta para el error inverso. Matriz esperada pero era objeto

    – Un jugador de críquet

    8 de julio de 2018 a las 19:21

¿Por que Gson fromJson arroja una excepcion JsonSyntaxException se esperaba
Sotirios Delimanolis

Como dice el mensaje de excepción

Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo

mientras deserializaba, Gson esperaba un objeto JSON, pero encontró una matriz JSON. Como no podía convertir de uno a otro, lanzó esta excepción.

El formato JSON se describe aquí. En resumen, define los siguientes tipos: objetos, arreglos, cadenas, números, nully los valores booleanos true y false.

En Gson (y en la mayoría de los analizadores JSON), existen las siguientes asignaciones: una cadena JSON se asigna a un Java String; un número JSON se asigna a un Java Number escribe; una matriz JSON se asigna a un Collection type o un tipo de matriz; un objeto JSON se asigna a un Java Map tipo o, típicamente, una costumbre POJO tipo (no mencionado anteriormente); null mapas a Java nully los valores booleanos se asignan a Java true y false.

Gson itera a través del contenido JSON que proporciona e intenta deserializarlo al tipo correspondiente que solicitó. Si el contenido no coincide o no se puede convertir al tipo esperado, generará la excepción correspondiente.

En su caso, proporcionó el siguiente JSON

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

En la raíz, este es un objeto JSON que contiene un miembro llamado nestedPojo que es una matriz JSON. Esa matriz JSON contiene un solo elemento, otro objeto JSON con dos miembros. Teniendo en cuenta las asignaciones definidas anteriormente, esperaría que este JSON se asigne a un objeto Java que tiene un campo llamado nestedPojo de algunas Collection o tipo de matriz, donde ese tipo define dos campos llamados name y valuerespectivamente.

Sin embargo, ha definido su Pojo escriba como si tuviera un campo

NestedPojo nestedPojo;

que no es ni un tipo de matriz, ni un Collection escribe. Gson no puede deserializar el JSON correspondiente para este campo.

En cambio, tienes 3 opciones:

  • Cambie su JSON para que coincida con el tipo esperado

    {
        "nestedPojo": {
            "name": null,
            "value": 42
        }
    }
    
  • Cambia tu Pojo escriba para esperar un Collection o tipo de matriz

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
    NestedPojo[] nestedPojo;
    
  • Escriba y registre un deserializador personalizado para NestedPojo con sus propias reglas de análisis. Por ejemplo

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

class Pojo {
  NestedPojo nestedPojo;
}

en su json tiene una matriz de Pojo anidado, así que cambia el código

  NestedPojo[] nestedPojo;

o cambias la cadena json

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad