W3docs

Java JSON mit Jackson

JSON in Java mit Jackson parsen, erzeugen und binden — ObjectMapper und Data Binding.

Jackson ist die de-facto-Standardbibliothek für JSON in Java. Das JDK liefert keine eigene JSON-API, weshalb nahezu jede Spring-, Quarkus- oder Micronaut-Anwendung Jackson verwendet, um Java-Objekte in JSON-Text umzuwandeln und umgekehrt. Der Einstiegspunkt ist eine einzige zentrale Klasse — ObjectMapper — die die zwei Aufgaben übernimmt, die man immer benötigt: Serialisierung (Java-Objekt → JSON) und Deserialisierung (JSON → Java-Objekt).

Wenn Sie neu bei JSON in Java sind, beginnen Sie mit der JSON-Einführung. Für eine schlankere alternative Bibliothek lesen Sie das Gson-Kapitel. Diese Seite behandelt das Hinzufügen von Jackson, die drei Ebenen seiner API, Data Binding, das Baummodell und die Annotationen, die das Mapping steuern.

Jackson zum Projekt hinzufügen

Jackson ist nicht Bestandteil des JDK, daher deklarieren Sie es als Abhängigkeit. Das Artefakt jackson-databind bindet die beiden anderen Kernmodule (jackson-core und jackson-annotations) transitiv ein.

<!-- Maven -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.17.1</version>
</dependency>
// Gradle
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'

Die drei Wege, mit JSON zu arbeiten

Jackson stellt dieselben Daten auf drei verschiedene Arten bereit. Wählen Sie die Ebene, die zur Aufgabe passt:

AnsatzKerntypVerwenden, wenn
Data BindingObjectMapper.readValue / writeValueSie haben ein POJO oder Record, das den JSON widerspiegelt — der häufigste Fall
BaummodellJsonNode über readTreeDie Struktur ist dynamisch oder Sie benötigen nur wenige Felder
StreamingJsonParser / JsonGeneratorSehr große Dokumente, die nicht vollständig im Speicher gehalten werden können

Data Binding verwenden Sie in 90 % der Fälle; die anderen beiden sind Ausweichmöglichkeiten.

Data Binding: Objekte rein, JSON raus

ObjectMapper.writeValueAsString serialisiert jedes Java-Objekt, indem es dessen Getter (oder Record-Komponenten) liest; readValue macht das Gegenteil und ordnet JSON-Feldnamen Ihren Feldern zu. Ein record ist das sauberste Ziel — Jackson 2.12+ bindet automatisch an seinen kanonischen Konstruktor, sodass Sie keine Getter oder einen No-Arg-Konstruktor schreiben müssen.

import com.fasterxml.jackson.databind.ObjectMapper;

record User(String name, int age, boolean active) {}

ObjectMapper mapper = new ObjectMapper();

// serialize: Java -> JSON
User ada = new User("Ada", 36, true);
String json = mapper.writeValueAsString(ada);
// {"name":"Ada","age":36,"active":true}

// deserialize: JSON -> Java
User back = mapper.readValue(json, User.class);
System.out.println(back.name()); // Ada

Für Collections und Generics übergeben Sie Jackson eine TypeReference, damit der Elementtyp die Typlöschung überlebt:

import com.fasterxml.jackson.core.type.TypeReference;

List<User> users = mapper.readValue(jsonArray, new TypeReference<List<User>>() {});

Das Baummodell: wenn die Struktur unbekannt ist

Wenn Sie keine passende Klasse haben (oder haben möchten), parsen Sie in einen generischen JsonNode-Baum und navigieren Sie ihn nach Schlüssel. Dies spiegelt wider, was ein manuell erstellter Map/List-Parser tut, aber mit typbewussten Accessoren wie asInt() und asText().

import com.fasterxml.jackson.databind.JsonNode;

JsonNode root = mapper.readTree(json);
String name = root.get("name").asText();
int age     = root.get("age").asInt();
JsonNode first = root.get("languages").get(0); // array access by index

Das Mapping mit Annotationen steuern

JSON-Feldnamen entsprechen selten perfekt den Java-Konventionen. Eine Handvoll Annotationen schließt die Lücke, ohne Ihre Feldnamen zu ändern:

AnnotationWirkung
@JsonProperty("user_name")Ein Feld auf einen anderen JSON-Schlüssel abbilden
@JsonIgnoreEin Feld in beide Richtungen auslassen
@JsonInclude(NON_NULL)null-Felder aus der Ausgabe weglassen
@JsonCreator / @JsonFormatBenutzerdefinierte Konstruktion / Datumsformatierung
record Account(
    @JsonProperty("user_name") String userName,
    @JsonIgnore String passwordHash) {}

Ein vollständiges Beispiel: serialisieren, parsen und manuell binden

Jackson ist im Classpath dieses Runners nicht vorhanden, daher baut das folgende Programm dieselben Konzepte nach — einen JSON-Writer, einen rekursiv-absteigenden Parser in einen Map/List-Baum und das Binden in einen record — ausschließlich mit java.util. Das ist genau das, was ObjectMapper im Hintergrund für Sie tut: einen Objektgraphen durchlaufen, um Text zu erzeugen, und Text tokenisieren, um einen Baum neu aufzubauen.

java— editable, runs on the server

Was man aus der Ausführung mitnimmt:

  • Serialisierung durchläuft einen Objektgraphen und erzeugt Text. Die serialized-Zeile zeigt eine verschachtelte Map/List, die zu {"name":"Ada",...,"languages":["Java","Ada"]} gerendert wird — ein Array innerhalb eines Objekts. ObjectMapper.writeValueAsString führt denselben rekursiven Durchlauf über die Getter Ihres POJOs oder die Komponenten eines Records durch.
  • Das Parsen baut zuerst einen generischen Baum auf. Der Laufzeittyp des geparsten Werts ist LinkedHashMap, nicht User — genau das Baummodell von Jackson, bei dem readTree einen JsonNode zurückgibt, den Sie nach Schlüssel navigieren, bevor eine Klasse beteiligt ist.
  • JSON-Zahlen werden zu Java-Zahlen, mit einer Typentscheidung. Das Feld age kam als Integer (42) zurück, weil der Text keinen Dezimalpunkt hatte; der Parser wählte Integer statt Double. Jackson trifft dieselbe Entscheidung, weshalb ein int-Feld sauber gebunden wird, während 3.14 als Double ankäme.
  • Der Feldzugriff erfolgt nach Name, und die Reihenfolge wird beibehalten. Die Verwendung von LinkedHashMap bewahrte die Schlüssel in Einfügereihenfolge, sodass name vor age gelesen wird. Jackson bewahrt die Schlüsselreihenfolge von Objekten auf dieselbe Weise, weshalb ein round-tripped JSON wie das Original aussieht.
  • Round-Tripping ist verlustfrei, wenn das Modell übereinstimmt. Die letzte Zeile re-serialisierte den geparsten Baum zum selben JSON, aus dem er stammte, und der typisierte User-Record band name, age und languages korrekt — der eigentliche Zweck von Data Binding: Text rein, Objekt raus, Text zurück, kein Datenverlust.

Übungen

Übung
Mit Jackson erhalten Sie eine JSON-Antwort, deren Struktur Sie nicht kontrollieren, und Sie müssen nur zwei Felder aus einem großen, tief verschachtelten Dokument lesen. Welcher Ansatz passt am besten?
Mit Jackson erhalten Sie eine JSON-Antwort, deren Struktur Sie nicht kontrollieren, und Sie müssen nur zwei Felder aus einem großen, tief verschachtelten Dokument lesen. Welcher Ansatz passt am besten?
Was this page helpful?