CodeGym /Cours /JAVA 25 SELF /Gson — sérialisation et désérialisation, configuration

Gson — sérialisation et désérialisation, configuration

JAVA 25 SELF
Niveau 46 , Leçon 2
Disponible

1. Introduction à Gson

Nous avons déjà découvert Jackson et vu pourquoi il est considéré comme le standard de facto pour travailler avec JSON en Java. Mais il existe une autre bibliothèque qui a gagné une immense popularité, surtout dans le monde Android — c’est Gson. Gson a été créé chez Google comme une solution légère et simple pour sérialiser et désérialiser des objets Java en JSON. On l’apprécie pour sa prise en main minimale : pour commencer à travailler, il n’y a presque rien à configurer — la plupart des tâches se résolvent littéralement « prêt à l’emploi ».

Un autre avantage de Gson réside dans sa légèreté. La bibliothèque occupe peu d’espace et n’entraîne pas de nombreuses dépendances, c’est pourquoi elle est souvent utilisée là où la taille de l’application est critique, par exemple sur les appareils mobiles. Gson est devenu un standard de fait pour les projets Android — compacité et simplicité y jouent un rôle décisif.

Au fait, le nom Gson signifie Google JSON. Il arrive que la communauté propose une interprétation humoristique — Genius’ Son (« fils de génie »), mais ce n’est évidemment pas officiel. Juste un jeu de mots.

Ajouter Gson au projet

Si vous utilisez Maven ou Gradle, ajoutez simplement la dépendance (la version peut varier) :

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'

Nous n’avons pas encore étudié l’assemblage de projets, donc pour commencer vous pouvez simplement télécharger le fichier jar depuis la page officielle de Gson et l’ajouter au projet.

2. Opérations de base : sérialisation et désérialisation

Voyons comment sérialiser et désérialiser des objets avec Gson sur l’exemple d’une classe simple.

Exemple : classe User

// Classe pour les exemples
public class User {
    private String name;
    private int age;
    private boolean active;

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

    // Getters et setters (Gson les utilise si nécessaire)
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
}

Sérialisation : objet → 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}
    }
}

Remarque : les champs sont sérialisés avec leurs noms tels que dans la classe !

Désérialisation : JSON → objet

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
    }
}

Travail avec des listes d’objets

Gson est un peu plus délicat avec les collections que Jackson, mais tout est gérable.

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}]

        // Désérialisation de la liste
        Type userListType = new TypeToken<List<User>>(){}.getType();
        List<User> users2 = gson.fromJson(json, userListType);
        System.out.println(users2.get(0).getName()); // Alice
    }
}

Point important : pour la désérialisation des collections, utilisez TypeToken<> !

3. Configuration de Gson : GsonBuilder

Gson offre une configuration flexible via la classe GsonBuilder. Avec elle, vous pouvez activer le pretty printing, la sérialisation de null, le formatage des dates et bien plus encore.

Exemple : pretty printing et sérialisation de 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()        // Affichage formaté (indentation)
            .serializeNulls()           // Sérialiser les champs null
            .create();

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

Formatage des dates

Si vous avez des champs de type Date, par défaut Gson les sérialise dans un format spécifique. Vous pouvez définir votre propre format :

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. Annotations Gson : contrôle de la sérialisation

Gson prend en charge des annotations pour un contrôle plus précis de la sérialisation et de la désérialisation.

@SerializedName — renommage de champ

Si vous souhaitez que le champ dans le JSON porte un autre nom, utilisez @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;
    }
}

Désormais, lors de la sérialisation, le champ s’appellera full_name :

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

@Expose — sérialiser uniquement les champs annotés

Si vous souhaitez sérialiser uniquement certains champs, utilisez @Expose et configurez Gson :

import com.google.gson.annotations.Expose;

public class User {
    @Expose
    private String name;

    @Expose
    private int age;

    private boolean active; // non sérialisé

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

Créons un Gson avec prise en charge de @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 — sérialisation conditionnelle par version
Vous pouvez utiliser @Since et @Until pour sérialiser des champs uniquement pour certaines versions (rarement utilisé en pratique, mais utile à connaître).

5. Particularités et limites de Gson

Travail avec des objets imbriqués

Gson fonctionne très bien avec des objets imbriqués :

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"}

Travail avec les collections

Pas de problème pour la sérialisation des collections (List, Map), mais pour la désérialisation utilisez TypeToken (voir ci‑dessus).

Limitations de Gson par rapport à Jackson

  • Pas de prise en charge des classes record Java (jusqu’aux versions récentes)
  • Prise en charge limitée des nouveaux API de types de date (par ex. LocalDate, LocalDateTime — des adaptateurs personnalisés sont nécessaires)
  • Pas de compatibilité avec les annotations Jackson
  • Pas de prise en charge des structures polymorphes complexes « prêt à l’emploi »
  • Pas de prise en charge automatique des références bidirectionnelles (cycles)

Adaptateurs personnalisés (TypeAdapter)

Si les fonctionnalités standard ne suffisent pas, vous pouvez écrire votre propre adaptateur pour sérialiser/désérialiser des types complexes.

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;
    }
}

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

6. Pratique : sérialisation et désérialisation avec configuration

Faisons évoluer votre application d’apprentissage et ajoutons l’enregistrement et le chargement d’une liste d’utilisateurs au format JSON.

Classe User avec annotations

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; // non sérialisé

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

    // getters, setters...
}

Sauvegarder la liste des utilisateurs en JSON

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("Ivan", 23, true),
            new User("Olga", 19, false)
        );

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

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

Charger la liste des utilisateurs depuis JSON

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\":\"Ivan\",\"age\":23},{\"full_name\":\"Olga\",\"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() + ")");
        }
        // Ivan (23)
        // Olga (19)
    }
}

7. Comparaison entre Gson et Jackson

Caractéristique Gson Jackson
Facilité d’utilisation +++++ (très simple) +++ (un peu plus complexe)
Taille de la bibliothèque Petite Plus grande
Vitesse Rapide, mais un peu plus lent Très rapide
Flexibilité Moyenne Élevée (plus d’options)
Prise en charge des annotations Propres (@SerializedName) Propres (@JsonProperty et autres)
Prise en charge des nouveaux types Limitée Excellente (Java 8+, record)
Prise en charge Android Excellente Bonne, mais plus lourde
Gestion des dates Uniquement via des adaptateurs Prêt à l’emploi
Polymorphisme Limité Flexible

8. Erreurs courantes avec Gson

Erreur n° 1 : vous n’utilisez pas TypeToken pour les collections.
Si vous désérialisez une liste ou une map, utilisez impérativement TypeToken<>, sinon vous obtiendrez des erreurs étranges ou des collections vides.

Erreur n° 2 : pas de constructeur sans argument.
Gson peut fonctionner sans constructeur par défaut, mais lors de la désérialisation d’objets complexes, des erreurs peuvent survenir sans un tel constructeur. Il est préférable d’ajouter systématiquement un constructeur sans argument si vous prévoyez une désérialisation.

Erreur n° 3 : incohérence des noms de champs.
Si, dans le JSON, le champ s’appelle "full_name" et, dans la classe, "name", sans l’annotation @SerializedName("full_name") le champ ne sera pas mappé et la valeur sera null.

Erreur n° 4 : problèmes avec les champs privés.
Gson peut sérialiser des champs privés, mais si vous n’avez que des champs privés et aucun getter/setter, il peut parfois y avoir des problèmes à la désérialisation. Il vaut mieux utiliser des getters et des setters.

Erreur n° 5 : gestion des dates.
Par défaut, Gson sérialise Date dans un format peu pratique. Pour LocalDate, LocalDateTime et d’autres nouveaux types, sans adaptateurs personnalisés vous aurez des erreurs de sérialisation.

Erreur n° 6 : vous n’utilisez pas @Expose, mais vous avez activé excludeFieldsWithoutExposeAnnotation().
Si vous avez activé excludeFieldsWithoutExposeAnnotation() mais n’avez pas annoté les champs avec @Expose, ils ne seront ni sérialisés ni désérialisés — le résultat sera un JSON vide ou des objets avec null.

1
Mission
JAVA 25 SELF, niveau 46, leçon 2
Bloqué
Synchronisation des données des étudiants avec un système externe 🎓
Synchronisation des données des étudiants avec un système externe 🎓
1
Mission
JAVA 25 SELF, niveau 46, leçon 2
Bloqué
Création de profils publics sur le réseau social 🌐
Création de profils publics sur le réseau social 🌐
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION