La sérialisation binaire en JAVA

Entant que développeur, on a recours à enregistrer l’état de nos objets dans la mémoire, fichier … Durant cet article, je vais essayer de présenter le mécanisme de la sérialisation comme solution, et son implémentation sous java.

Définition
La sérialisation est le processus de sauvegarde de l’état d’un objet à destination d’une zone de stockage. La désérialisation est le processus inverse, donc reconstituer l’objet depuis un flux de données.

Sérialisation JAVA

Il existe plusieurs type de sérialisation tels que : La sérialisation binaire, la sérialisation XML…

Sérialisation # Persistance
Il ne faut pas confondre entre la sérialisation et la persistance, la première consiste à une conversion d’un objet en flux de données donc pas de notion de stockage. Quant à  la persistance fait référence au stockage permanent. A vrai dire, la sérialisation peut être utilisé pour assurer la persistance des objets.

La sérialisation a été introduit dans java depuis sa version 1.1. Pour réaliser ce mécanisme sous java, on a besoin de l’interface Serializable, les classes ObjectOutputStream et ObjectInputStream. Une autre interface peut être ajoutée qui est l’interface Externalizable qui nous permet d’implémenter notre propre mécanisme de sérialisation (cet article ne traite pas la sérialisation personnalisée).

L’interface Serializable est interface qui permet d’identifier les classes sérialisables. Donc, pour sérialiser un objet d’une classe donnée, elle doit implémenter l’interface Serializable ou hérite d’une classe elle-même serialisable.
Pour qu’un attribut soit Sérialisé il doit être :

  • De type primitif ou être lui-même serialisable.
  • Pas déclaré en tant que static.
  • Pas déclaré en tant que transient.
  • Ne pas être hérité d’une classe mère non serialisable.

N.B :
Un numéro de version « serialVersionUID » est associé à toute classe serialisable, il permet de tester la correspondance des classes lors de la déserialisation.

Toute classe sérialisable doit comporter l’attribut « serialVersionUID » dite le numéro de version. Son rôle est de s’assurer des versions des classes JAVA. Il est de la forme :

private static final long serialVersionUID = 1L;

Afin d’illustrer un exemple pour notre article, on va utiliser la classe suivante :

public class User{

        private  String nom;
        private  String pass;

        public  User(String nom, String pass)
        {
                this.nom=nom;
                this.pass=pass;
        }

        public  String get_nom()
        {
                return  nom;
        }

        public  String get_pass()
        {
                return  pass;
        }
}

La sérialisation :
La classe ObjectOutputStream représente un flux d’objets, elle implémente l’interface « ObjectOutput » qui nous fournie la possibilité d’écriture des objets. Ainsi, la classe ObjectOutputSteram permet de sérialiser un objet via sa méthode « writeObject() » comme le nous montre la méthode suivant :

public static void serialiser(User user)
{
        try  {
                FileOutputStream  fout=new FileOutputStream("auth.bin");
                ObjectOutputStream  oout=new ObjectOutputStream(fout);
                oout.writeObject(user);
                System.out.println(user.get_nom()  + " a ete serialise");
                oout.close();
                fout.close();
        }  catch(IOException ioe) {
                ioe.printStackTrace();
        }
}

En gros au modo, cette méthode permet la sérialisation d’un objet User,  mais voyons un peu ce qui existe dans la marmite. Pour sérialiser notre objet on a besoin d’un fichier  (Comme sorte de moyen stockage) pour contenir nos objets, à cette fin on a créé l’objet fout « FileOutputStream » qui as comme paramètre le chemin du fichier « auth.bin » (vous pouvez passer le chemin ou même l’objet FileOutputStream comme paramètre à la méthode).

La création d’un objet ObjectOutputStream qui prend comme paramètre l’instance FileOutputStream va nous permettre de sérialiser l’objet User dans le fichier « auth.bin ».
L’objet oout de la classe ObjectOutputStream prend comme paramètre l’objet fout va nous permettre de sérialiser notre objet user de la classe User grâce à sa méthode writeObject(). La clôture des objets oout et fout ainsi que le traitement des exceptions est primordiale.

La déserialisation :
La classe ObjectInputStream implémente l’interface « ObjectInput » qui nous fournie la possibilité de lire carrément un objet à partir d’un flux de données tels que les fichiers. Donc la déserialisation est déployée grâce aux objets de la classe ObjectInputStream via la méthode « readObject() » qui retourne à un objet de la classe Object, comme nous le montre cette exemple :

public static User deserialiser()
{
        User  user=null;
        try  {
                FileInputStream  fin=new FileInputStream("auth.bin");
                ObjectInputStream  oin=new ObjectInputStream(fin);
                user=(User)oin.readObject();
                System.out.println(user.get_nom()  + " a ete deserialise");
                oin.close();
                fin.close();
        }catch(ClassNotFoundException  nfe) {
                nfe.printStackTrace();
        }  catch(IOException ioe) {
                ioe.printStackTrace();
        }
        return  user;
}

Cette méthode permet de désérialiser un objet User, il s’agit d’une lecture de l’objet à partir du fichier « auth.bin ». En effet, pour la lecture des objets nous avons besoin de l’objet fin de la classe FileInputStream qui prend comme paramètre le chemin du fichier « auth.bin » (vous pouvez passer le chemin ou même l’objet FileInputStream comme paramètre à la méthode).

L’objet oin de la classe ObjectInputStream qui prend comme paramètre l’objet fin permet de lire un objet depuis le fichier « auth.bin » via l’appel de la méthode readObject(), donc il va falloir faire un cast pour retourner un objet User. Idem à la sérialisation, la clôture des fin et oin ainsi que le traitement des exceptions est primordiale.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class User implements Serializable {

        private static final long serialVersionUID = 1L;
        private String nom;
        private String pass;

        public User(String nom, String pass) {
                this.nom = nom;
                this.pass = pass;
        }

        public String get_nom() {
                return nom;
        }

        public String get_pass() {
                return pass;
        }

        public static void serialiser(User user) {
                try {
                        FileOutputStream fout = new FileOutputStream("auth.bin");
                        ObjectOutputStream oout = new ObjectOutputStream(fout);
                        oout.writeObject(user);
                        System.out.println(user.get_nom() + " a été serialisé");
                        oout.close();
                        fout.close();
                } catch (IOException ioe) {
                        ioe.printStackTrace();
                }
        }

        public static User deserialiser() {
                User user = null;
                try {
                        FileInputStream fin = new FileInputStream("auth.bin");
                        ObjectInputStream oin = new ObjectInputStream(fin);
                        user = (User) oin.readObject();
                        System.out.println(user.get_nom() + " a été deserialise");
                        oin.close();
                        fin.close();
                } catch (ClassNotFoundException nfe) {
                        nfe.printStackTrace();
                } catch (IOException ioe) {
                        ioe.printStackTrace();
                }
                return user;
        }
}

La sérialisation partielle :
Jusqu’à maintenant, on a vu la sérialisation et la déserialisation mais il semble que ces mécanises prend en charge tout les attributs de la classes!!! Pas du tout, pour une raison ou une autre on ne veut sérialiser qu’une partie des attributs et cela est réalisé grâce au mot clé transient. Comme exemple pour la classe User, pour des raisons de sécurité,  on ne va pas sérialiser le mot de passe et donc la classe devienne comme suit :

public class User implements Serializable{

private static  final long serialVersionUID = 1L;
private String nom;
transient  private String pass;

}

A propos de l'auteur

Faut il vraiment porter des lunettes, pour travailler la nuit, sur un terminal vert sur noire, pour être Geek pour devenir root ?