Gson — eine Bibliothek von Google zur Serialisierung von Java-Objekten in JSON und zurück, die in der Android-Entwicklung weit verbreitet ist. Sie ermöglicht die Konvertierung komplexer Objektgraphen in kompakte JSON-Strings, ohne Parser manuell schreiben zu müssen. Laut Google Gson, 2024 hat die Bibliothek über 23.000 Sterne auf GitHub und bleibt eine der beliebtesten Lösungen für die Arbeit mit JSON im Java- und Kotlin-Ökosystem.
Wichtige Punkte
Gson ist eine von Google entwickelte Java-Bibliothek zur Konvertierung von Objekten in JSON-Darstellung und zurück. Sie verwendet Reflektion zur Analyse der Klassenstruktur, was ein Arbeiten ohne vorherige Konfiguration ermöglicht. Gson unterstützt beliebige Java-Objekte, Sammlungen, Arrays, Generics und verschachtelte Klassen. Die Bibliothek erfordert keine Annotationen für die grundlegende Verwendung, stellt sie aber zur Feineinstellung bereit. Der Hauptnachteil der Reflektion ist die reduzierte Leistung während der Initialisierung und die Unfähigkeit zur Optimierung zur Kompilierzeit, was besonders beim Kaltstart einer Android-Anwendung beim Deserialisieren hunderter Modelle auffällt. Trotzdem bleibt Gson dank seiner Stabilität und umfangreichen Dokumentation eine zuverlässige Wahl für die meisten Projekte.
Gson wurde 2008 von Google veröffentlicht und schnell zum De-facto-Standard für JSON in Android-Anwendungen. Vor dem Aufkommen von Moshi und kotlinx.serialization war Gson die einzige beliebte Wahl für Kotlin-Projekte. Einfache Integration — Hinzufügen einer einzigen Abhängigkeit zu build.gradle — und das Fehlen obligatorischer Annotationen machten Gson bei Entwicklern aller Erfahrungsstufen beliebt.
// Gson in build.gradle hinzufügen
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
}
// Grundlegende Verwendung
data class User(
val id: Int,
val name: String,
val email: String
)
val gson = Gson()
val user = User(1, "John", "john@test.com")
val json = gson.toJson(user)
println(json) // {"id":1,"name":"John","email":"john@test.com"}
Neben der grundlegenden Serialisierung bietet Gson GsonBuilder zur Konfiguration des Verhaltens: Datumsformatierung, Deaktivierung von HTML-Escaping, Schreibweise von Schlüsseln und benutzerdefinierte Instanzen. GsonBuilder ermöglicht auch die Registrierung benutzerdefinierter JsonSerializer und JsonDeserializer für Typen, die die Bibliothek nicht automatisch verarbeiten kann. Die Konfigurationsflexibilität macht GsonBuilder zu einem unverzichtbaren und nützlichen Werkzeug bei der Anpassung der Bibliothek an spezifische Projektanforderungen in der modernen Android-Entwicklung.
toJson konvertiert ein Java-Objekt durch Analyse seiner Felder mittels Reflektion in einen JSON-String. Standardmäßig schließt Gson alle Felder außer transient und static ein. Die Methode unterstützt beliebige Typen: Primitive, Objekte, Sammlungen und Arrays. fromJson führt die umgekehrte Operation aus, akzeptiert einen JSON-String und die Zielobjektklasse und gibt eine Instanz mit gefüllten Feldern zurück.
Während der Serialisierung durchläuft Gson rekursiv alle Objektfelder, einschließlich verschachtelter. Zyklische Referenzen führen zu StackOverflowError, daher müssen sie durch die @Expose-Annotation oder einen benutzerdefinierten Adapter ausgeschlossen werden. Für Sammlungen bewahrt Gson die Elementtypen, aber beim Deserialisieren einer Liste mit Generics ist TypeToken erforderlich, um Typinformationen zu erhalten.
// data class mit verschachteltem Objekt
data class Address(
val city: String,
val street: String
)
data class Employee(
val id: Int,
val name: String,
val address: Address
)
val gson = Gson()
val employee = Employee(1, "Alice",
Address("New York", "5th Ave"))
// Serialisierung in JSON
val json = gson.toJson(employee)
// Deserialisierung aus JSON
val jsonString = """
{"id":2,"name":"Bob","address":{"city":"London","street":"Baker St"}}
"""
val parsed = gson.fromJson(jsonString, Employee::class.java)
Gson bietet eine Reihe von Annotationen zur Verwaltung des Serialisierungsprozesses. @SerializedName gibt den Namen des JSON-Schlüssels an, der vom Feldnamen abweicht. @Expose steuert, ob ein Feld in die Serialisierung einbezogen wird: Ein über GsonBuilder.excludeFieldsWithoutExposeAnnotation() erstelltes Gson verarbeitet nur Felder mit @Expose. @Since und @Until steuern die Feldversionierung.
Die @SerializedName-Annotation löst das Problem der Namensinkonsistenz: Der Server verwendet möglicherweise snake_case, während im Code camelCase verwendet wird. Die Annotation akzeptiert einen Wert und optionale Alternativen für die Abwärtskompatibilität. @Expose ermöglicht das Ausblenden sensibler Felder (Passwörter, Token) aus der Serialisierung, indem sie als @Expose(serialize = false) markiert werden. Neben Ein- und Ausschluss kann @Expose mit GsonBuilder.excludeFieldsWithoutExposeAnnotation kombiniert werden, um eine Whitelist von Feldern zu erstellen, was hilft, die Angriffsfläche bei der Serialisierung von Objekten mit vielen Feldern zu kontrollieren.
// Modell mit Gson-Annotationen
data class UserResponse(
@SerializedName("user_id")
val userId: Int,
@SerializedName("full_name",
alternate = [Alternative("name")])
val fullName: String,
@Expose(serialize = false)
val password: String
)
// Gson mit @Expose-Filterung
val gson = GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create()
val user = UserResponse(1, "John", "secret123")
println(gson.toJson(user))
// {"user_id":1,"full_name":"John"} — Passwort ausgeschlossen
Das Generics-Problem in Java und Kotlin ist das Type-Erasure zur Kompilierzeit. Wenn Gson List<User> deserialisiert, kennt es den Elementtyp nicht und gibt List<Map<String, Any>> zurück. Um Typinformationen zu erhalten, bietet Gson TypeToken — eine abstrakte Klasse, die den Typparameter durch eine anonyme Klasse erfasst. Ohne TypeToken müsste der Entwickler jedes Element manuell von Map in den Zieltyp konvertieren, was zu umständlichem Code und Leistungseinbußen führt.
TypeToken löst das Problem des Type-Erasure. Der Entwickler erstellt eine anonyme Unterklasse von TypeToken mit dem erforderlichen Typparameter, und Gson verwendet die Informationen aus der Klassensignatur für die korrekte Deserialisierung. TypeToken funktioniert auch mit Map, Set und allen anderen parametrisierten Typen, einschließlich verschachtelter Generics. Insbesondere für Map<String, List<User>> ist ein TypeToken mit der vollständigen verschachtelten Typsignatur erforderlich, sonst deserialisiert Gson Werte als List<Map<String, Any>> statt List<User>.
// TypeToken für Listendeserialisierung
data class Product(
val id: Int,
val title: String,
val price: Double
)
val jsonArray = """
[
{"id":1,"title":"Phone","price":599.0},
{"id":2,"title":"Laptop","price":1299.0}
]
"""
val gson = Gson()
val listType = object : TypeToken<List<Product>>() {}
val products: List<Product> =
gson.fromJson(jsonArray, listType.type)
// Benutzerdefinierter Deserialisierer
class LocalDateAdapter :
JsonDeserializer<LocalDate> {
override fun deserialize(
json: JsonElement,
typeOfT: java.lang.reflect.Type,
context: JsonDeserializationContext
): LocalDate {
return LocalDate.parse(json.asString)
}
}
Für benutzerdefinierte Serialisierungslogik unterstützt Gson die Schnittstellen JsonSerializer und JsonDeserializer. Sie werden über GsonBuilder.registerTypeAdapter() registriert und ermöglichen die Verarbeitung von Typen, die die Bibliothek nicht automatisch serialisieren kann: Java-8-Daten, Enums mit nicht standardmäßigen Werten oder Drittanbieterklassen ohne Zugriff auf den Quellcode. Bei der Implementierung eines Adapters ist die Leistungsüberwachung wichtig: Das Aufrufen von Reflektion innerhalb eines benutzerdefinierten Adapters macht die Vorteile der manuellen Steuerung zunichte, daher sind direkte Methoden- und Feldaufrufe vorzuziehen. Im Gson-Ökosystem gibt es auch das Modul gson-extras, das Adapter für gängige Typen wie UUID, Optional und Joda-Time-Datumsräder bereitstellt.
GsonBuilder bietet Dutzende von Methoden zur Feineinstellung der Serialisierung. setPrettyPrinting fügt Einzüge und Zeilenumbrüche zum Ausgabe-JSON hinzu, um die Lesbarkeit zu verbessern. disableHtmlEscaping deaktiviert das Escapen von HTML-Zeichen in Strings. setDateFormat legt das Datumsformat fest, was bei der Arbeit mit Servern, die nicht standardmäßige Zeitdarstellungen verwenden, kritisch ist. setLenient aktiviert den nachsichtigen Parsing-Modus, der bestimmte JSON-Formatierungsfehler ignoriert. addDeserializationExclusionStrategy ermöglicht den programmatischen Ausschluss von Feldern aus der Deserialisierung basierend auf benutzerdefinierten Strategien. Zum Debuggen ist setPrettyPrinting in Kombination mit Logging nützlich — es macht JSON-Antworten in Logs lesbar und vereinfacht die Suche nach Unstimmigkeiten.
Eine wichtige Funktion von GsonBuilder ist die Versionsverwaltung von Feldern durch @Since- und @Until-Annotationen. Der Entwickler gibt die Objektversion über setVersion an, und Gson schließt Felder automatisch basierend auf ihrer Versionsannotation ein oder aus. Dies ist nützlich bei der API-Evolution, wenn dasselbe Modell für verschiedene Versionen des Serverprotokolls verwendet wird. GsonBuilder unterstützt auch die Registrierung von TypeAdapterFactory zur globalen Verarbeitung von Familientypen und complexMapKeySerialization für die korrekte Arbeit mit komplexen Map-Schlüsseln.
Häufig gestellte Fragen
Gson ist eine Google-Bibliothek zum Konvertieren von Java-Objekten in JSON und zurück. Sie wird in Android-Anwendungen häufig zum Parsen von Serverantworten, Serialisieren von Anfragen und Speichern von Daten im lokalen Speicher verwendet.
Standardmäßig überspringt Gson null-Felder während der Serialisierung. Um null-Werte einzuschließen, verwenden Sie GsonBuilder.serializeNulls(). Bei der Deserialisierung bleiben fehlende Felder in JSON null oder nehmen den Standardwert des Typs an.
Moshi verwendet keine Reflektion für Kotlin-Klassen, was eine höhere Leistung und vorhersagbares Verhalten bietet. Moshi behandelt auch die Kotlin-Null-Sicherheit korrekt, während Gson null in ein Non-Null-Feld deserialisieren kann, was eine Ausnahme auslöst.
@SerializedName bindet einen JSON-Schlüssel an ein Klassenfeld, wenn ihre Namen nicht übereinstimmen. Zum Beispiel für das Feld kotlinName und den JSON-Schlüssel "kotlin_name" sorgt die Annotation @SerializedName("kotlin_name") für die korrekte Konvertierung.
TypeToken ist eine abstrakte Klasse, die den Typparameter durch eine anonyme Klasse erfasst. Sie ist notwendig für die Deserialisierung von Sammlungen und anderen parametrisierten Typen, da Gson aufgrund von Type-Erasure den Elementtyp zur Laufzeit nicht wiederherstellen kann.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch