Pourquoi Gson de Json lève-t-il une exception JsonSyntaxException: BEGIN_OBJECT attendue mais BEGIN_ARRAY?

(Ce message est censé être une question canonique avec un exemple de réponse fourni ci-dessous.)


J’essaie de désérialiser du contenu JSON dans un type POJO personnalisé avec Gson#fromJson(Ssortingng, Class) .

Ce morceau de code

 import com.google.gson.Gson; public class Sample { public static void main(Ssortingng[] args) { Ssortingng json = "{\"nestedPojo\":[{\"name\":null, \"value\":42}]}"; Gson gson = new Gson(); gson.fromJson(json, Pojo.class); } } class Pojo { NestedPojo nestedPojo; } class NestedPojo { Ssortingng name; int value; } 

jette l’exception suivante

 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 

Pourquoi Gson ne peut-il pas convertir correctement mon texte JSON en mon type POJO?

Comme l’indique le message d’exception

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

lors de la désérialisation, Gson attendait un object JSON, mais a trouvé un tableau JSON. Puisqu’il ne pouvait pas convertir l’un à l’autre, il a jeté cette exception.

Le format JSON est décrit ici . En bref, il définit les types suivants: objects, tableaux, chaînes, nombres, null et les valeurs booléennes true et false .

Dans Gson (et la plupart des parsingurs JSON), les mappages suivants existent: une chaîne JSON est mappée sur une Ssortingng Java; un numéro JSON correspond à un type de Number Java; un tableau JSON correspond à un type de Collection ou à un type de tableau; un object JSON mappe vers un type de Map Java ou, généralement, un type de POJO personnalisé (non mentionné précédemment); null correspond à la valeur null de Java et les valeurs booléennes correspondent à la valeur true et false de Java.

Gson effectue une itération sur le contenu JSON que vous fournissez et essaie de le désérialiser au type correspondant demandé. Si le contenu ne correspond pas ou ne peut pas être converti dans le type attendu, une exception correspondante sera levée.

Dans votre cas, vous avez fourni le code JSON suivant:

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

À la racine, il s’agit d’un object JSON contenant un membre nommé nestedPojo qui est un tableau JSON. Ce tableau JSON contient un seul élément, un autre object JSON avec deux membres. Compte tenu des mappages définis précédemment, vous vous attendez à ce que JSON mappe à un object Java comportant un champ nommé nestedPojo de type Collection ou tableau, où ces types définissent deux champs nommés name et value , respectivement.

Cependant, vous avez défini votre type de Pojo comme ayant un champ

 NestedPojo nestedPojo; 

ce n’est ni un type de tableau, ni un type de Collection . Gson ne peut pas désérialiser le JSON correspondant à ce champ.

Au lieu de cela, vous avez 3 options:

  • Changez votre JSON pour correspondre au type attendu

     { "nestedPojo": { "name": null, "value": 42 } } 
  • Changez votre type de Pojo pour attendre un type de Collection ou de tableau

     List nestedPojo; // consider changing the name and using @SerializedName NestedPojo[] nestedPojo; 
  • Écrivez et enregistrez un désérialiseur personnalisé pour NestedPojo avec vos propres règles d’parsing. Par exemple

     class Custom implements JsonDeserializer { @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.getAsSsortingng(); } nestedPojo.value = jsonObject.get("value").getAsInt(); return nestedPojo; } } Gson gson = new GsonBuilder().registerTypeAdapter(NestedPojo.class, new Custom()).create(); 
 class Pojo { NestedPojo nestedPojo; } 

dans votre json vous avez un tableau de nestedPojo donc soit vous changez le code

  NestedPojo[] nestedPojo; 

ou vous changez la chaîne json

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