CodeGym /Kurse /JAVA 25 SELF /Gson — Serialisierung und Deserialisierung, Konfiguration...

Gson — Serialisierung und Deserialisierung, Konfiguration

JAVA 25 SELF
Level 46 , Lektion 2
Verfügbar

1. Einführung in Gson

Wir haben uns bereits mit Jackson vertraut gemacht und gesehen, warum es als De-facto-Standard für die Arbeit mit JSON in Java gilt. Es gibt jedoch eine weitere Bibliothek, die enorme Popularität gewonnen hat, besonders in der Android-Welt — nämlich Gson. Gson wurde bei Google als leichtgewichtiges und einfaches Werkzeug zur Serialisierung und Deserialisierung von Java-Objekten in JSON entwickelt. Es wird für seine sehr niedrige Einstiegshürde geschätzt: Um loszulegen, muss man kaum etwas konfigurieren — die meisten Aufgaben funktionieren praktisch „out of the box“.

Ein weiterer Vorteil von Gson ist seine Leichtgewichtigkeit. Die Bibliothek ist klein und bringt nicht viele Abhängigkeiten mit, weshalb sie oft dort eingesetzt wird, wo die Größe der Anwendung kritisch ist, zum Beispiel auf mobilen Geräten. Gson ist zum faktischen Standard für Android-Projekte geworden — Kompaktheit und Einfachheit spielen dort eine entscheidende Rolle.

Übrigens steht der Name Gson für Google JSON. In der Community findet man manchmal eine scherzhafte Deutung — Genius’ Son („Sohn eines Genies“), das ist natürlich inoffiziell. Einfach ein Wortspiel.

Gson ins Projekt einbinden

Wenn Sie Maven oder Gradle verwenden, fügen Sie einfach die Abhängigkeit hinzu (die Version kann variieren):

Maven:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>

Gradle:

implementation 'com.google.code.gson:gson:2.10.1'

Wir haben den Projekt-Build noch nicht behandelt, daher können Sie für den Anfang einfach die JAR-Datei von der offiziellen Gson-Seite herunterladen und zum Projekt hinzufügen.

2. Basisoperationen: Serialisierung und Deserialisierung

Schauen wir uns an, wie man Objekte mit Gson serialisiert und deserialisiert – am Beispiel einer einfachen Klasse.

Beispiel: Klasse User

// Beispielklasse
public class User {
    private String name;
    private int age;
    private boolean active;

    // Konstruktor
    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }

    // Getter und Setter (Gson verwendet sie bei Bedarf)
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
}

Serialisierung: Objekt → JSON

import com.google.gson.Gson;

public class GsonExample {
    public static void main(String[] args) {
        User user = new User("Alice", 25, true);

        Gson gson = new Gson();
        String json = gson.toJson(user);

        System.out.println(json);
        // {"name":"Alice","age":25,"active":true}
    }
}

Beachten Sie: Felder werden mit ihren Namen aus der Klasse serialisiert!

Deserialisierung: JSON → Objekt

public class GsonExample {
    public static void main(String[] args) {
        String json = "{\"name\":\"Bob\",\"age\":30,\"active\":false}";

        Gson gson = new Gson();
        User user = gson.fromJson(json, User.class);

        System.out.println(user.getName()); // Bob
        System.out.println(user.getAge());  // 30
        System.out.println(user.isActive());// false
    }
}

Arbeiten mit Objektlisten

Gson arbeitet mit Collections etwas umständlicher als Jackson, aber das ist lösbar.

import java.util.List;
import java.util.Arrays;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;

public class GsonListExample {
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
            new User("Alice", 25, true),
            new User("Bob", 30, false)
        );

        Gson gson = new Gson();
        String json = gson.toJson(users);
        System.out.println(json);
        // [{"name":"Alice","age":25,"active":true},{"name":"Bob","age":30,"active":false}]

        // Deserialisierung einer Liste
        Type userListType = new TypeToken<List<User>>(){}.getType();
        List<User> users2 = gson.fromJson(json, userListType);
        System.out.println(users2.get(0).getName()); // Alice
    }
}

Wichtiger Hinweis: Für die Deserialisierung von Collections verwenden Sie TypeToken<>!

3. Gson konfigurieren: GsonBuilder

Gson bietet eine flexible Konfiguration über die Klasse GsonBuilder. Damit können Sie Pretty Printing aktivieren, null-Werte serialisieren, Datumsformate festlegen und vieles mehr.

Beispiel: Pretty Printing und Serialisierung von null

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonBuilderExample {
    public static void main(String[] args) {
        User user = new User("Charlie", 0, false);

        Gson gson = new GsonBuilder()
            .setPrettyPrinting()        // Hübsche Ausgabe (Einrückungen)
            .serializeNulls()           // Null-Felder serialisieren
            .create();

        String json = gson.toJson(user);
        System.out.println(json);
        /*
        {
          "name": "Charlie",
          "age": 0,
          "active": false
        }
        */
    }
}

Datumsformatierung

Wenn Sie Felder vom Typ Date haben, serialisiert Gson sie standardmäßig in einem spezifischen Format. Sie können ein eigenes Format vorgeben:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Date;

public class DateExample {
    private String event;
    private Date date;

    public DateExample(String event, Date date) {
        this.event = event;
        this.date = date;
    }
}

public class Main {
    public static void main(String[] args) {
        DateExample meeting = new DateExample("Team Meeting", new Date());

        Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd HH:mm:ss")
            .create();

        String json = gson.toJson(meeting);
        System.out.println(json);
        // {"event":"Team Meeting","date":"2024-06-10 13:45:23"}
    }
}

4. Gson-Annotationen: Serialisierung steuern

Gson unterstützt Annotationen für eine feinere Kontrolle der Serialisierung und Deserialisierung.

@SerializedName — Feld umbenennen

Wenn ein Feld im JSON anders heißen soll, verwenden Sie @SerializedName:

import com.google.gson.annotations.SerializedName;

public class User {
    @SerializedName("full_name")
    private String name;
    private int age;
    private boolean active;

    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }
}

Jetzt heißt das Feld bei der Serialisierung full_name:

User user = new User("Diana", 28, true);
String json = new Gson().toJson(user);
// {"full_name":"Diana","age":28,"active":true}

@Expose — nur markierte Felder serialisieren

Wenn Sie nur bestimmte Felder serialisieren möchten, verwenden Sie @Expose und konfigurieren Sie Gson entsprechend:

import com.google.gson.annotations.Expose;

public class User {
    @Expose
    private String name;

    @Expose
    private int age;

    private boolean active; // wird nicht serialisiert

    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }
}

Wir erstellen ein Gson mit Unterstützung für @Expose:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

Gson gson = new GsonBuilder()
    .excludeFieldsWithoutExposeAnnotation()
    .create();

User user = new User("Eve", 21, false);
String json = gson.toJson(user);
// {"name":"Eve","age":21}

@Since/@Until — bedingte Serialisierung nach Version
Sie können @Since und @Until verwenden, um Felder nur für bestimmte Versionen zu serialisieren (in der Praxis selten genutzt, aber hilfreich zu kennen).

5. Besonderheiten und Einschränkungen von Gson

Arbeiten mit verschachtelten Objekten

Gson funktioniert sehr gut mit verschachtelten Objekten:

public class Profile {
    private User user;
    private String bio;

    public Profile(User user, String bio) {
        this.user = user;
        this.bio = bio;
    }
}

Profile profile = new Profile(new User("Frank", 27, true), "Java developer");
String json = new Gson().toJson(profile);
// {"user":{"name":"Frank","age":27,"active":true},"bio":"Java developer"}

Arbeiten mit Collections

Mit der Serialisierung von Collections (List, Map) gibt es keine Probleme, aber für die Deserialisierung verwenden Sie TypeToken (siehe oben).

Einschränkungen von Gson im Vergleich zu Jackson

  • Keine Unterstützung für Java record-Klassen (bis zu den neuesten Versionen)
  • Eingeschränkte Unterstützung der neuen Date/Time-API (z. B. LocalDate, LocalDateTime — erfordern benutzerdefinierte Adapter)
  • Unterstützt Jackson-Annotationen nicht
  • Keine Unterstützung komplexer polymorpher Strukturen out of the box
  • Keine automatische Unterstützung bidirektionaler Referenzen (Zyklen)

Eigene Adapter (TypeAdapter)

Wenn die Standardmöglichkeiten nicht ausreichen, können Sie einen eigenen Adapter zum Serialisieren/Deserialisieren komplexer Typen schreiben.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;

public class BooleanAsIntAdapter extends TypeAdapter<Boolean> {
    @Override
    public void write(JsonWriter out, Boolean value) throws IOException {
        out.value(value ? 1 : 0);
    }

    @Override
    public Boolean read(JsonReader in) throws IOException {
        return in.nextInt() == 1;
    }
}

// Verwendung:
Gson gson = new GsonBuilder()
    .registerTypeAdapter(Boolean.class, new BooleanAsIntAdapter())
    .create();

6. Praxis: Serialisierung und Deserialisierung mit Konfiguration

Lassen Sie uns Ihre Lernanwendung erweitern und das Speichern und Laden einer Benutzerliste im JSON-Format hinzufügen.

Klasse User mit Annotationen

import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;

public class User {
    @Expose
    @SerializedName("full_name")
    private String name;

    @Expose
    private int age;

    private boolean active; // wird nicht serialisiert

    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }

    // Getter, Setter ...
}

Benutzerliste als JSON speichern

import java.util.List;
import java.util.Arrays;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SaveUsers {
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
            new User("John", 23, true),
            new User("Jane", 19, false)
        );

        Gson gson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .setPrettyPrinting()
            .create();

        String json = gson.toJson(users);
        System.out.println(json);
        /*
        [
          {
            "full_name": "John",
            "age": 23
          },
          {
            "full_name": "Jane",
            "age": 19
          }
        ]
        */
    }
}

Benutzerliste aus JSON laden

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;

public class LoadUsers {
    public static void main(String[] args) {
        String json = "[{\"full_name\":\"John\",\"age\":23},{\"full_name\":\"Jane\",\"age\":19}]";

        Gson gson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .create();

        Type userListType = new TypeToken<List<User>>(){}.getType();
        List<User> users = gson.fromJson(json, userListType);

        for (User user : users) {
            System.out.println(user.getName() + " (" + user.getAge() + ")");
        }
        // John (23)
        // Jane (19)
    }
}

7. Vergleich: Gson und Jackson

Merkmal Gson Jackson
Einfachheit der Nutzung +++++ (sehr einfach) +++ (etwas komplexer)
Bibliotheksgröße Klein Größer
Geschwindigkeit Schnell, aber etwas langsamer Sehr schnell
Flexibilität Mittel Hoch (mehr Einstellungen)
Unterstützung für Annotationen Eigene (@SerializedName) Eigene (@JsonProperty u. a.)
Unterstützung neuer Typen Eingeschränkt Ausgezeichnet (Java 8+, record)
Android-Unterstützung Ausgezeichnet Gut, aber schwergewichtiger
Umgang mit Datumswerten Nur über Adapter Ab Werk
Polymorphismus Begrenzt Flexibel konfigurierbar

8. Typische Fehler im Umgang mit Gson

Fehler Nr. 1: Sie verwenden TypeToken nicht für Collections.
Wenn Sie eine Liste oder Map deserialisieren, verwenden Sie unbedingt TypeToken<>, sonst erhalten Sie seltsame Fehler oder leere Collections.

Fehler Nr. 2: Kein parameterloser Konstruktor.
Gson kommt zwar auch ohne Standardkonstruktor aus, aber bei der Deserialisierung komplexer Objekte kann es ohne einen solchen zu Problemen kommen. Fügen Sie besser immer einen parameterlosen Konstruktor hinzu, wenn Sie Deserialisierung planen.

Fehler Nr. 3: Feldnamen stimmen nicht überein.
Wenn im JSON das Feld "full_name" heißt, in der Klasse aber "name", wird ohne die Annotation @SerializedName("full_name") das Feld nicht gemappt und der Wert ist null.

Fehler Nr. 4: Probleme mit privaten Feldern.
Gson kann private Felder serialisieren, aber wenn es nur private Felder gibt und keine Getter/Setter, entstehen bei der Deserialisierung mitunter Probleme. Verwenden Sie besser Getter und Setter.

Fehler Nr. 5: Umgang mit Datumswerten.
Standardmäßig serialisiert Gson Date in einem unpraktischen Format. Für LocalDate, LocalDateTime und andere neue Typen kommt es ohne benutzerdefinierte Adapter zu Serialisierungsfehlern.

Fehler Nr. 6: @Expose nicht verwendet, aber excludeFieldsWithoutExposeAnnotation() aktiviert.
Wenn Sie excludeFieldsWithoutExposeAnnotation() aktiviert haben, die Felder aber nicht mit @Expose markiert sind, werden sie weder serialisiert noch deserialisiert — das Ergebnis ist ein leeres JSON oder Objekte mit null.

1
Aufgabe
JAVA 25 SELF, Level 46, Lektion 2
Gesperrt
Synchronisierung von Studentendaten mit einem externen System 🎓
Synchronisierung von Studentendaten mit einem externen System 🎓
1
Aufgabe
JAVA 25 SELF, Level 46, Lektion 2
Gesperrt
Erstellung öffentlicher Profile im sozialen Netzwerk 🌐
Erstellung öffentlicher Profile im sozialen Netzwerk 🌐
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION