CodeGym /Cours /JAVA 25 SELF /Analyse des erreurs courantes lors de la sérialisation de...

Analyse des erreurs courantes lors de la sérialisation des collections

JAVA 25 SELF
Niveau 44 , Leçon 4
Disponible

1. NotSerializableException : quand une collection refuse de se sérialiser

L’erreur la plus fréquente et la plus insidieuse lors de la sérialisation des collections — c’est java.io.NotSerializableException. Elle survient si au moins un élément de la collection n’implémente pas l’interface Serializable.

Voyons un exemple naïf :

import java.io.*;
import java.util.*;

class Book {
    String title;
    Book(String title) { this.title = title; }
}

public class LibraryApp {
    public static void main(String[] args) throws Exception {
        List<Book> books = new ArrayList<>();
        books.add(new Book("Dombey et fils"));

        // Tentative de sérialiser la collection
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("books.ser"))) {
            oos.writeObject(books); // BOUM ! NotSerializableException
        }
    }
}

Que va-t-il se passer ? À l’étape oos.writeObject(books), vous obtiendrez l’exception suivante :

java.io.NotSerializableException: Book

Pourquoi ? Parce que la classe Book n’implémente pas l’interface Serializable. Même si la collection elle-même (ArrayList) sait se sérialiser, les éléments de la collection doivent eux aussi être sérialisables !

Comment diagnostiquer

L’erreur indique toujours la classe à l’origine du problème — cherchez-la dans le message d’exception. Si la collection est volumineuse et que l’erreur n’apparaît que dans certaines conditions, il est possible qu’un élément ait été ajouté par inadvertance et n’implémente pas Serializable.

Comment corriger

Ajoutez implements Serializable à votre classe :

class Book implements Serializable {
    String title;
    Book(String title) { this.title = title; }
}

Conseil : Si la collection contient différents types d’objets, vérifiez qu’ils implémentent tous Serializable !

2. ClassCastException lors de la désérialisation : quand les génériques vous piègent

En Java, l’information sur les paramètres génériques des collections est effacée après compilation (type erasure). Cela signifie que si vous avez sérialisé List<String> et que vous désérialisez en tant que List<Integer>, le compilateur ne verra pas l’erreur, mais à l’exécution vous obtiendrez un ClassCastException.

Exemple :

// Sérialisation
List<String> names = Arrays.asList("Anna", "Boris");
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("names.ser"))) {
    oos.writeObject(names);
}

// Désérialisation (DANGEREUX !)
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("names.ser"))) {
    List<Integer> numbers = (List<Integer>) ois.readObject(); // unchecked cast
    Integer first = numbers.get(0); // BOUM ! ClassCastException
}

Erreur :

java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer

Comment éviter

  • N’utilisez pas de collections « brutes » (raw types) et n’effectuez pas de transtypages sans nécessité.
  • Vérifiez les types des éléments après la désérialisation si vous n’êtes pas sûr de leur contenu.
  • Documentez le type de collection sérialisé et celui attendu à la lecture.

Exemple de désérialisation sûre :

Object obj = ois.readObject();
if (obj instanceof List<?>) {
    List<?> list = (List<?>) obj;
    if (!list.isEmpty() && list.get(0) instanceof String) {
        @SuppressWarnings("unchecked")
        List<String> safeNames = (List<String>) obj; // avertissement supprimé, mais le type a été vérifié !
    }
}

3. Modification de la structure des classes : serialVersionUID et rétrocompatibilité

Vous avez sérialisé une collection, puis décidé d’ajouter un nouveau champ à la classe de l’élément, de renommer un champ ou de changer la structure de la classe. Maintenant, lors de la tentative de désérialiser l’ancien fichier, vous obtenez une erreur mystérieuse :

java.io.InvalidClassException: Book; local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 5678

Pourquoi cela arrive-t-il

Chaque classe sérialisable reçoit un identifiant de version unique — serialVersionUID. Si la classe a changé (par exemple, vous avez ajouté un champ), la JVM calcule un nouveau serialVersionUID, et la désérialisation constate que la version de la classe ne correspond pas à celle utilisée lors de la sérialisation.

Comment éviter

  • Déclarez explicitement serialVersionUID dans vos classes :
class Book implements Serializable {
    private static final long serialVersionUID = 1L;
    String title;
    // ...
}
  • Préservez la rétrocompatibilité : n’effacez pas et ne renommez pas les champs si vous prévoyez de lire d’anciens fichiers.
  • Testez la désérialisation après les modifications.

Que faire s’il faut malgré tout modifier la classe ?

  • Envisagez d’implémenter les méthodes readObject/writeObject pour piloter manuellement la sérialisation.
  • Ou migrez les données : lisez l’ancien fichier avec l’ancienne version de la classe, puis réenregistrez au nouveau format.

4. Perte de données lors de la sérialisation des collections immuables

Dans les versions récentes de Java, des collections immuables sont apparues, par exemple créées via List.of(), Set.of(), Map.of(). Dans les anciennes versions de Java (avant 12) et certaines implémentations tierces, la sérialisation de telles collections peut mal fonctionner : après désérialisation, la collection devient ordinaire et modifiable ou une erreur se produit carrément.

Exemple :

List<String> list = List.of("a", "b", "c");
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.ser"))) {
    oos.writeObject(list);
}

Sur d’anciennes JVM, une erreur survenait à la désérialisation, ou la collection cessait d’être immuable.

Comment éviter

  • Vérifiez la documentation de la version de Java que vous utilisez.
  • Testez la sérialisation et la désérialisation de ces collections.
  • Si vous devez préserver l’immuabilité, après désérialisation, encapsulez la collection avec Collections.unmodifiableList(list).

5. Sérialisation des champs transient et static

Que se passe-t-il pour ces champs :

  • transient — les champs marqués par ce mot-clé ne sont pas du tout sérialisés. Après la désérialisation, ils auront la valeur par défaut (par exemple, null ou 0).
  • static — les champs de classe (et non d’instance) ne sont jamais sérialisés.

Exemple :

class Book implements Serializable {
    String title;
    transient String cache; // n’est pas sérialisé !
    static String publisher = "Default"; // non plus sérialisé !
}

Pourquoi est-ce important

Si vous stockez des valeurs calculées ou un cache à l’intérieur de l’objet, marquez-les comme transient — cela économise de l’espace et accélère la sérialisation.

Attention : après désérialisation, les champs transient doivent être recalculés ou réinitialisés.

6. Sérialisation de grandes collections : performances et taille de fichier

Problèmes :

  • Les grandes collections (p. ex., un million d’objets) peuvent conduire à des fichiers énormes, à des temps d’écriture et de lecture très longs, et parfois même à un manque de mémoire (OutOfMemoryError).
  • Lors de la sérialisation d’un graphe d’objets (par exemple, des collections complexes interconnectées), la taille du fichier peut croître de manière inattendue.

Comment éviter

  • Sérialisez la collection par morceaux : par exemple, écrivez les objets un par un ou par petites séries.
  • Utilisez un traitement en flux : au lieu de sérialiser toute la collection d’un coup, sérialisez les éléments au fil de l’eau.
  • Compressez les fichiers : utilisez GZIPOutputStream pour réduire la taille du fichier.

Exemple de sérialisation en flux :

try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("books.ser"))) {
    for (Book book : bigList) {
        oos.writeObject(book);
    }
}

Attention : avec cette approche, la désérialisation doit savoir combien d’objets ont été écrits (ou utiliser un « marqueur de fin »).

1
Étude/Quiz
Sérialisation de structures complexes, niveau 44, leçon 4
Indisponible
Sérialisation de structures complexes
Sérialisation de structures complexes
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION