Gson — une bibliothèque de Google pour sérialiser des objets Java en JSON et inversement, largement utilisée dans le développement Android. Elle permet de convertir des graphes d'objets complexes en chaînes JSON compactes sans écrire de parseurs manuellement. Selon Google Gson, 2024, la bibliothèque compte plus de 23 000 étoiles sur GitHub et reste l'une des solutions les plus populaires pour travailler avec JSON dans l'écosystème Java et Kotlin.
Points Clés
Gson est une bibliothèque Java développée par Google pour convertir des objets en représentation JSON et inversement. Elle utilise la réflexion pour analyser la structure des classes, ce qui permet de travailler sans configuration préalable. Gson prend en charge les objets Java arbitraires, les collections, les tableaux, les génériques et les classes imbriquées. La bibliothèque ne nécessite pas d'annotations pour une utilisation de base, mais en fournit pour un réglage fin. Le principal inconvénient de la réflexion est la réduction des performances lors de l'initialisation et l'incapacité d'optimiser au moment de la compilation, ce qui est particulièrement notable au démarrage à froid d'une application Android lors de la désérialisation de centaines de modèles. Malgré cela, Gson reste un choix fiable pour la plupart des projets grâce à sa stabilité et sa documentation complète.
Gson a été publié par Google en 2008 et est rapidement devenu le standard de facto pour JSON dans les applications Android. Avant l'arrivée de Moshi et kotlinx.serialization, Gson était le seul choix populaire pour les projets Kotlin. La facilité d'intégration — ajouter une seule dépendance à build.gradle — et l'absence d'annotations obligatoires ont rendu Gson populaire parmi les développeurs de tous niveaux.
// Ajouter Gson dans build.gradle
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
}
// Utilisation de base
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"}
En plus de la sérialisation de base, Gson fournit GsonBuilder pour configurer le comportement : formatage des dates, désactivation de l'échappement HTML, casse des clés et instances personnalisées. GsonBuilder permet également d'enregistrer des JsonSerializer et JsonDeserializer personnalisés pour les types que la bibliothèque ne peut pas traiter automatiquement. La flexibilité de configuration fait de GsonBuilder un outil indispensable et utile lors de l'adaptation de la bibliothèque aux exigences spécifiques du projet dans le développement Android moderne.
toJson convertit un objet Java en une chaîne JSON en analysant ses champs par réflexion. Par défaut, Gson inclut tous les champs sauf transient et static. La méthode prend en charge tous les types : primitifs, objets, collections et tableaux. fromJson effectue l'opération inverse, acceptant une chaîne JSON et la classe de l'objet cible, et retourne une instance avec les champs remplis.
Lors de la sérialisation, Gson parcourt récursivement tous les champs de l'objet, y compris les champs imbriqués. Les références cycliques entraînent une StackOverflowError, elles doivent donc être exclues via l'annotation @Expose ou un adaptateur personnalisé. Pour les collections, Gson préserve les types d'éléments, mais lors de la désérialisation d'une liste avec des génériques, TypeToken est nécessaire pour conserver les informations de type.
// data class avec objet imbriqué
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"))
// Sérialisation en JSON
val json = gson.toJson(employee)
// Désérialisation depuis JSON
val jsonString = """
{"id":2,"name":"Bob","address":{"city":"London","street":"Baker St"}}
"""
val parsed = gson.fromJson(jsonString, Employee::class.java)
Gson fournit un ensemble d'annotations pour gérer le processus de sérialisation. @SerializedName spécifie le nom de la clé JSON qui diffère du nom du champ. @Expose contrôle si un champ est inclus dans la sérialisation : Gson créé via GsonBuilder.excludeFieldsWithoutExposeAnnotation() ne traitera que les champs avec @Expose. @Since et @Until contrôlent le versionnage des champs.
L'annotation @SerializedName résout le problème de non-concordance des noms : le serveur peut utiliser snake_case alors que le code utilise camelCase. L'annotation accepte une valeur et des alternatives optionnelles pour la rétrocompatibilité. @Expose permet de masquer les champs sensibles (mots de passe, jetons) de la sérialisation en les marquant comme @Expose(serialize = false). En plus de l'inclusion et de l'exclusion, @Expose peut être combiné avec GsonBuilder.excludeFieldsWithoutExposeAnnotation pour créer une liste blanche de champs, ce qui aide à contrôler la surface d'attaque lors de la sérialisation d'objets avec de nombreux champs.
// Modèle avec annotations Gson
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 avec filtrage @Expose
val gson = GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create()
val user = UserResponse(1, "John", "secret123")
println(gson.toJson(user))
// {"user_id":1,"full_name":"John"} — mot de passe exclu
Le problème des génériques en Java et Kotlin est l'effacement de type au moment de la compilation. Lorsque Gson désérialise List<User>, il ne connaît pas le type d'élément et retourne List<Map<String, Any>>. Pour préserver les informations de type, Gson fournit TypeToken — une classe abstraite qui capture le paramètre de type via une classe anonyme. Sans TypeToken, le développeur devrait convertir manuellement chaque élément de Map vers le type cible, ce qui entraîne un code lourd et une perte de performance.
TypeToken résout le problème d'effacement de type. Le développeur crée une sous-classe anonyme de TypeToken avec le paramètre de type requis, et Gson utilise les informations de la signature de classe pour une désérialisation correcte. TypeToken fonctionne également avec Map, Set et tout autre type paramétré, y compris les génériques imbriqués. En particulier, pour Map<String, List<User>>, un TypeToken avec la signature de type imbriqué complète est requis, sinon Gson désérialise les valeurs comme List<Map<String, Any>> au lieu de List<User>.
// TypeToken pour la désérialisation de liste
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)
// Désérialiseur personnalisé
class LocalDateAdapter :
JsonDeserializer<LocalDate> {
override fun deserialize(
json: JsonElement,
typeOfT: java.lang.reflect.Type,
context: JsonDeserializationContext
): LocalDate {
return LocalDate.parse(json.asString)
}
}
Pour la logique de sérialisation personnalisée, Gson prend en charge les interfaces JsonSerializer et JsonDeserializer. Elles sont enregistrées via GsonBuilder.registerTypeAdapter() et permettent de traiter les types que la bibliothèque ne peut pas sérialiser automatiquement : les dates Java 8, les Enum avec des valeurs non standard ou les classes tierces sans accès au code source. Lors de l'implémentation d'un adaptateur, il est important de surveiller les performances : appeler la réflexion dans un adaptateur personnalisé annule les avantages du contrôle manuel, donc les appels directs aux méthodes et champs sont préférables. Dans l'écosystème Gson, il existe également le module gson-extras qui fournit des adaptateurs pour les types courants comme UUID, Optional et les roues de date Joda-Time.
GsonBuilder fournit des dizaines de méthodes pour le réglage fin de la sérialisation. setPrettyPrinting ajoute des indentations et des sauts de ligne au JSON de sortie pour la lisibilité. disableHtmlEscaping désactive l'échappement des caractères HTML dans les chaînes. setDateFormat spécifie le format de date, ce qui est critique lors du travail avec des serveurs utilisant des représentations temporelles non standard. setLenient active le mode d'analyse tolérant, qui ignore certaines erreurs de formatage JSON. addDeserializationExclusionStrategy permet d'exclure programmatiquement des champs de la désérialisation sur la base de stratégies personnalisées. Pour le débogage, setPrettyPrinting combiné avec la journalisation est utile — il rend les réponses JSON lisibles dans les journaux et simplifie la recherche d'incohérences.
Une fonctionnalité importante de GsonBuilder est la gestion du versionnage des champs via les annotations @Since et @Until. Le développeur spécifie la version de l'objet via setVersion, et Gson inclut ou exclut automatiquement les champs en fonction de leur annotation de version. Ceci est utile lors de l'évolution de l'API, lorsque le même modèle est utilisé pour différentes versions du protocole serveur. GsonBuilder prend également en charge l'enregistrement de TypeAdapterFactory pour le traitement global des types de famille et complexMapKeySerialization pour un travail correct avec les clés complexes de Map.
Foire Aux Questions
Gson est une bibliothèque Google pour convertir des objets Java en JSON et inversement. Elle est largement utilisée dans les applications Android pour analyser les réponses du serveur, sérialiser les requêtes et stocker des données dans le stockage local.
Par défaut, Gson ignore les champs null lors de la sérialisation. Pour inclure les valeurs null, utilisez GsonBuilder.serializeNulls(). Lors de la désérialisation, les champs absents du JSON restent null ou prennent la valeur par défaut du type.
Moshi n'utilise pas la réflexion pour les classes Kotlin, ce qui offre des performances plus élevées et un comportement prévisible. Moshi gère également correctement la sécurité null de Kotlin, tandis que Gson peut désérialiser null dans un champ non null, provoquant une exception.
@SerializedName lie une clé JSON à un champ de classe lorsque leurs noms ne correspondent pas. Par exemple, pour le champ kotlinName et la clé JSON "kotlin_name", l'annotation @SerializedName("kotlin_name") garantit une conversion correcte.
TypeToken est une classe abstraite qui capture le paramètre de type via une classe anonyme. Il est nécessaire pour désérialiser les collections et autres types paramétrés, car en raison de l'effacement de type, Gson ne peut pas récupérer le type d'élément au moment de l'exécution.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi