(Dieser Beitrag soll eine kanonische Frage mit einer Beispielantwort unten sein.)
Ich versuche, einige JSON-Inhalte in einen benutzerdefinierten POJO-Typ mit zu deserialisieren Gson#fromJson(String, Class)
.
Dieses Stück 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;
}
wirft die folgende Ausnahme
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
Warum kann Gson meinen JSON-Text nicht richtig in meinen POJO-Typ konvertieren?
Wie die Ausnahmemeldung besagt
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo
Beim Deserialisieren erwartete Gson ein JSON-Objekt, fand aber ein JSON-Array. Da es nicht von einem zum anderen konvertieren konnte, hat es diese Ausnahme ausgelöst.
Das JSON-Format wird beschrieben Hier. Kurz gesagt definiert es die folgenden Typen: Objekte, Arrays, Strings, Zahlen, null
und die booleschen Werte true
und false
.
In Gson (und den meisten JSON-Parsern) gibt es die folgenden Zuordnungen: Eine JSON-Zeichenfolge wird einem Java zugeordnet String
; Eine JSON-Nummer wird einem Java zugeordnet Number
Art; ein JSON-Array wird a zugeordnet Collection
Typ oder ein Array-Typ; Ein JSON-Objekt wird einem Java zugeordnet Map
Typ oder, in der Regel, eine benutzerdefinierte POJO Typ (vorher nicht erwähnt); null
Karten zu Java null
und die booleschen Werte werden Java zugeordnet true
und false
.
Gson durchläuft den von Ihnen bereitgestellten JSON-Inhalt und versucht, ihn in den entsprechenden angeforderten Typ zu deserialisieren. Wenn der Inhalt nicht übereinstimmt oder nicht in den erwarteten Typ konvertiert werden kann, wird eine entsprechende Ausnahme ausgelöst.
In Ihrem Fall haben Sie das folgende JSON bereitgestellt
{
"nestedPojo": [
{
"name": null,
"value": 42
}
]
}
An der Wurzel ist dies ein JSON-Objekt, das ein Mitglied mit dem Namen enthält nestedPojo
das ist ein JSON-Array. Dieses JSON-Array enthält ein einzelnes Element, ein weiteres JSON-Objekt mit zwei Mitgliedern. In Anbetracht der zuvor definierten Zuordnungen würden Sie erwarten, dass dieser JSON-Code einem Java-Objekt zugeordnet wird, das ein benanntes Feld hat nestedPojo
von einigen Collection
oder Array-Typ, wobei dieser Typ zwei benannte Felder definiert name
und value
bzw.
Allerdings haben Sie Ihre definiert Pojo
Typ als mit einem Feld
NestedPojo nestedPojo;
das ist weder ein Array-Typ noch ein Collection
Art. Gson kann den entsprechenden JSON-Code für dieses Feld nicht deserialisieren.
Stattdessen haben Sie 3 Möglichkeiten:
-
Ändern Sie Ihr JSON so, dass es dem erwarteten Typ entspricht
{
"nestedPojo": {
"name": null,
"value": 42
}
}
-
Ändere dein Pojo
Typ erwarten a Collection
oder Array-Typ
List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
NestedPojo[] nestedPojo;
-
Schreiben und registrieren Sie einen benutzerdefinierten Deserializer für NestedPojo
mit eigenen Parsing-Regeln. Zum Beispiel
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;
}
In Ihrem JSON haben Sie ein Array von nestedPojo, also ändern Sie entweder den Code
NestedPojo[] nestedPojo;
oder Sie ändern den JSON-String
String json = "{\"nestedPojo\":{\"name\":null, \"value\":42}}";
Es könnte sich lohnen, eine zweite Antwort für den inversen Fehler hinzuzufügen. Erwartetes Array, war aber Objekt
– OneCricketeer
8. Juli 2018 um 19:21 Uhr