[JAVA] Maîtrisez les java.io.notserializableexception

Bonjour à tous,

Aujourd’hui un tout petit article qui fait suite aux rendus de projet il y a maintenant un peu plus d’un mois. Je suis entrain de tout recommenter en anglais pour pouvoir partager mes projets sur Git et j’en profite pour corriger quelques bugs que je n’avais pu résoudre à l’époque.

Dans mon projet de simulation de trafic de véhicules (que vous retrouverez bientôt sur mon Git), j’ai implémenté un système de sauvegarde du jeu (enfin de la simulation). Tous les objets nécessaires sont sauvegardés à l’aide de l’interface Serializable à implémenter dans chacun d’eux. Puis on sauvegarde le tout :

oos = new ObjectOutputStream(
          new BufferedOutputStream(
              new FileOutputStream(new File(path))));
oos.writeObject(object_to_save);

Petit problème ! J’ai quelques BufferedImage qui se baladent dans mes objets à sauvegarder (ou serializer en anglicisme assumé) qui me lancent donc une formidable exception du type : java.io.notserializableexception. Après avoir rajouté le mot clé transient devant chaque BufferedImage et « rusé » pour récupérer à nouveau les images quand on chargera la sauvegarde avec l’astuce suivante :

ois = new ObjectInputStream(
          new BufferedInputStream(
              new FileInputStream(new File(path))));
object_to_save = (Class of object_to_save)ois.readObject();
object_to_save.load();

Dans la classe représentant l’objet object_to_save, il suffit d’ajouter un String contenant le chemin de l’image à afficher qu’il sera donc possible de sérializer. Ensuite, load() permet d’instancier la BufferedImage qui est dans l’object_to_save.

public void load(){
    try{
        bufferedImage = ImageIO.read(new File(string));
    } catch (IOException e) {
        System.out.println("No image found at "+string);
    }
}

Là tout marche ! Mais en fait il reste un cas spécial, bien difficile à déceler. Il s’agit des classes internes (nested ou inner class). J’avais personnellement (je ne sais pour quelle raison) mis un enum en classe interne d’un JFrame (je ne comprends toujours pas ma logique). Sauf que cet enum devait être serializable.

Et là, grosse catastrophe, alors que tous mes BufferedImage étaient marqués en transient pour tous mes objets serializables, la sauvegarde ne marchait pas avec l’exception java.io.notserializableexception. Eh bien, après un petit tour dans la javadoc, j’apprends qu’une classe interne si elle est déclarée serializable, rendra sa classe « mère » aussi serializable même si vous ne l’avez pas déclarée ainsi (et que la plupart du temps, ca n’a pas de sens !).

Un petit récapitulatif donc :

public class MyObject implements Serializable{
    private BufferedImage bufferedImage;
}

Ne marche pas pour la sauvegarde. Pour contourner celà, utilisez l’astuce suivante :

public class myClass implements Serializable{
    private transient BufferedImage bufferedImage;
    private String string;

    public void load(){
        try{
             bufferedImage = ImageIO.read(new File(string));
        } catch (IOException e) {
             System.out.println("No image found at "+string);
        }
    }
}

Ensuite quand vous chargerez votre sauvegarde, n’oubliez pas d’appeler la méthode load de votre objet !

Pour les classes internes, voici ce qu’il ne faut pas faire :

public class mySuperClass{
    public class myInnerClass implements Serializable{}
}

Ceci rend mySuperClass serializable ! Pire, quand vous serializerez un objet de la classe myInnerClass, il serializera automatiquement un objet de la classe mySuperClass ! Pour résoudre ce « problème », déclarez toujours des classes implémentant Serializable en classe « normale » et pas interne !

Source :

Serialization of inner classes (i.e., nested classes that are not static member classes), including local and anonymous classes, is strongly discouraged for several reasons. Because inner classes declared in non-static contexts contain implicit non-transient references to enclosing class instances, serializing such an inner class instance will result in serialization of its associated outer class instance as well.

http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s