2015-11-10 12 views
5

(Questo post vuole essere un canonical question con una risposta esempio fornito di seguito.)Perché Gson di Johnson lancia una JSONSyntaxException: Si aspettava un certo tipo ma era un altro tipo?


Sto cercando di deserializzare alcuni contenuti JSON in un tipo di POJO personalizzato con Gson#fromJson(String, Class).

questo pezzo di codice

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

genera l'eccezione follow

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 

Perché non è possibile convertire il GSON correttamente il mio testo JSON per il mio tipo POJO?

risposta

22

Come il messaggio di eccezione afferma

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

durante la deserializzazione, GSON si aspettava un oggetto JSON, ma ha trovato una matrice JSON. Dal momento che non poteva convertire da uno all'altro, ha lanciato questa eccezione.

Il formato JSON è descritto here. In breve, definisce i seguenti tipi: oggetti, matrici, stringhe, numeri, null e i valori booleani true e false.

In Gson (e nella maggior parte dei parser JSON), esistono i seguenti mapping: una stringa JSON associa a Java String; un numero JSON si associa a un tipo Java Number; un array JSON esegue il mapping su un tipo Collection o un tipo di matrice; un oggetto JSON esegue il mapping su un tipo Java Map o, in genere, su un tipo personalizzato POJO (non indicato in precedenza); null esegue il mapping a Java null ei valori booleani corrispondono a Java true e false.

Gson itera attraverso il contenuto JSON che fornisci e prova a deserializzare nel tipo corrispondente che hai richiesto. Se il contenuto non corrisponde o non può essere convertito nel tipo previsto, genererà un'eccezione corrispondente.

Nel tuo caso, si forniscono le seguenti JSON

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

Alla radice, questo è un oggetto JSON che contiene un membro denominato nestedPojo, che è una matrice JSON. Quella matrice JSON contiene un singolo elemento, un altro oggetto JSON con due membri. Considerando i mapping definiti in precedenza, ci si aspetterebbe che questo JSON eseguisse la mappatura su un oggetto Java che ha un campo denominato Collection o tipo di matrice nestedPojo, dove tali tipi definiscono rispettivamente due campi denominati name e value.

Tuttavia, avete definito il tipo di Pojo come avere un campo

NestedPojo nestedPojo; 

che non è né un tipo di matrice, né un tipo Collection. Gson non può deserializzare il JSON corrispondente per questo campo.

Invece, si hanno 3 opzioni:

  • cambiare la vostra JSON in base al tipo previsto

    { 
        "nestedPojo": { 
         "name": null, 
         "value": 42 
        } 
    } 
    
  • Cambiare il tipo di Pojo aspettarsi un tipo Collection o un array

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName 
    NestedPojo[] nestedPojo; 
    
  • Scrivi e reg ister un deserializzatore personalizzato per NestedPojo con le tue regole di analisi. Per esempio

    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(); 
    
7
class Pojo { 
    NestedPojo nestedPojo; 
} 

in JSON si dispone di una serie di nestedPojo quindi o si modifica il codice di

NestedPojo[] nestedPojo; 

o si modifica la stringa JSON

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