(Ce message est censé être un question canonique avec un exemple de réponse fourni ci-dessous.)
J'essaie de désérialiser du contenu JSON en un type POJO personnalisé avec Gson#fromJson(String, Class)
.
Ce morceau de 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;
}
lève l'exception de suivi
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 objet JSON, mais a trouvé un tableau JSON. Puisqu'il ne pouvait pas se convertir de l'un à l'autre, il a levé cette exception.
Le format JSON est décrit ici . En bref, il définit les types suivants: objets, tableaux, chaînes, nombres, null
et les valeurs booléennes true
et false
.
Dans Gson (et la plupart des analyseurs JSON), les mappages suivants existent: une chaîne JSON correspond à un Java String
; un numéro JSON correspond à un Java Number
type; un tableau JSON correspond à un type Collection
ou un type tableau; un objet JSON correspond à un Java Map
tapez ou, typiquement, un type personnalisé [~ # ~] pojo [~ # ~] (non mentionné précédemment); null
correspond au null
de Java et les valeurs booléennes au true
et false
de Java.
Gson parcourt le contenu JSON que vous fournissez et essaie de le désérialiser au type correspondant que vous avez demandé. Si le contenu ne correspond pas ou ne peut pas être converti au type attendu, il lèvera une exception correspondante.
Dans votre cas, vous avez fourni le JSON suivant
{
"nestedPojo": [
{
"name": null,
"value": 42
}
]
}
À la racine, il s'agit d'un objet JSON qui contient un membre nommé nestedPojo
qui est un tableau JSON. Ce tableau JSON contient un seul élément, un autre objet JSON avec deux membres. Compte tenu des mappages définis précédemment, vous vous attendriez à ce que ce JSON soit mappé à un objet Java qui a un champ nommé nestedPojo
d'un certain Collection
ou type de tableau, où ce type définit deux champs nommés name
et value
, respectivement.
Cependant, vous avez défini votre type Pojo
comme ayant un champ
NestedPojo nestedPojo;
ce n'est ni un type de tableau, ni un type Collection
. Gson ne peut pas désérialiser le JSON correspondant pour ce champ.
Au lieu de cela, vous avez 3 options:
Modifiez votre JSON pour qu'il corresponde au type attendu
{
"nestedPojo": {
"name": null,
"value": 42
}
}
Modifiez votre type Pojo
pour vous attendre à un type Collection
ou tableau
List<NestedPojo> 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'analyse. Par exemple
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;
}
dans votre json, vous avez un tableau de nestedPojo donc soit vous changez le code
NestedPojo[] nestedPojo;
ou vous changez la chaîne json
String json = "{\"nestedPojo\":{\"name\":null, \"value\":42}}";