IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Sérialisation de différentes versions de données


Sujet :

Entrée/Sortie Java

  1. #1
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut Sérialisation de différentes versions de données
    Bonjour,

    j'ai créé une classe de données qui sauvegarde celles-ci sous forme de fichier, grâce au mécanisme de sérialisation.

    Cette classe possède un serialVersionUID, afin de pouvoir gérer les différentes évolutions de la structure de données.

    Par exemple, le N° de série initial vaut 1.
    Lorsque je rajouterai d'autres éléments de données, je ferai évoluer le serialVersionUID à 2, etc...

    L'idée est de permettre à la classe version 2, de pouvoir quand même charger des données issues d'un fichier en version 1.

    Question: comment récupérer le serialVersionUID d'un fichier afin d'effectuer le traitement approprié lors du chargement du fichier ?
    @ bientôt...

    Salut & @+ sur 3W!

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Un serialVersionUID différent te bloquera la sérialisation !

    Il faut conserver le même serialVersionUID, et les champs manquant seront mis à null (ou zéro pour les type primitif).

    A la rigueur tu peux utiliser la méthode readResolve() pour leurs donner une valeur différentes...


    a++

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2010
    Messages : 54
    Points : 74
    Points
    74
    Par défaut
    Si tu veux un bon controle sur la sérialisation/désérialisation au cours des différentes version, particulièrement si dans le temps les noms de champ changeront, il faut implémenter Externalizable et non pas Serializable, et garder le serialVersionUID constant (il est là justement pour permettre au mécanisme de désérialisation de détecter les versions incompatibles)

  4. #4
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut
    Merci pour vos réponses.

    En résumé si j'ai bien compris, il faut que je gère moi-même les évolutions de mes données, en y intégrant par exemple un N° de version.

    Je pensais que le serialVersionID servait justement à détecter les différentes évolutions, et permettre ensuite le traitement appproprié en fonction de la version. Du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    switch( serialVersionID )
    {
    case 1:
      chargeDonneesVersion1();
      break;
     
    case 2:
      chargeDonneesVersion2();
     
      etc...
    }
    @ bientôt...

    Salut & @+ sur 3W!

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2010
    Messages : 54
    Points : 74
    Points
    74
    Par défaut
    non, tu ne peux pas, tu aura cette exception, même avec externalizable:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    java.io.InvalidClassException: TestSerialisation; local class incompatible: stream classdesc serialVersionUID = 10, local class serialVersionUID = 100
    	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
    	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
    	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
    	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    	at TestSerialisation.main(TestSerialisation.java:26)
    Voici un code avec une des manières suggérée de gérer l'évolution (via readResolve et writeReplace )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.ObjectStreamException;
    import java.io.OutputStream;
    import java.io.Serializable;
     
     
    public class TestSerialisation implements Serializable{
     
     
    	public static class HolderV1 implements Serializable{
    		private static final long serialVersionUID = 100L;
    		private String s;
    		public HolderV1(TestSerialisation testSerialisation) {
    			s=testSerialisation.s;
    		}
    		protected Object readResolve() throws ObjectStreamException{
    			// sera appelé par les code ayant sérialisé grâce à HolderV1
    			System.out.println("readResolve V1");
    			TestSerialisation t = new TestSerialisation();
    			t.s=s;
    			t.s2=null; // s2 n'existait pas encore dans la version 1 de la sérialisation
    			return t;
    		}
    	}
    	public static class HolderV2 implements Serializable{
    		private static final long serialVersionUID = 200L;
    		private String s;
    		private String s2;
    		public HolderV2(TestSerialisation testSerialisation) {
    			s=testSerialisation.s;
    			s2=testSerialisation.s2;
    		}
    		protected Object readResolve() throws ObjectStreamException{
    			// sera appelé par les code ayant sérialisé grâce à HolderV2
    			System.out.println("readResolve V2");
    			TestSerialisation t = new TestSerialisation();
    			t.s=s;
    			t.s2=s2;
    			return t;
     
    		}
    	}
    	private static final long serialVersionUID = 100L;
    	private String s = "blabla";
    	private String s2 = "blibli";
     
    	public String toString(){
    		return s+"/"+s2;
    	}
     
    	public static boolean flagVersionNouvelle = false ; // juste pour le test ;)
    	public static void main(String[] argv) throws IOException, ClassNotFoundException{
    		// test d'évolution de version
     
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		ObjectOutputStream oos = new ObjectOutputStream(baos);
    		TestSerialisation t = new TestSerialisation();
    		System.out.println("serialisation avec ancien code de la nouvelle classe: "+t);
    		oos.writeObject(t); // on simule l'écriture avec une vieille version
    		oos.flush();
    		oos.close();
    		System.out.println("désérialisation....");
    		TestSerialisation t2 = (TestSerialisation) new ObjectInputStream(
    				new ByteArrayInputStream(
    						baos.toByteArray()
    						)
    				).readObject(); // on lit avec le code "générique"
     
    		System.out.println("désérialisé suivant code générique: "+t2);
    		baos = new ByteArrayOutputStream();
    		oos = new ObjectOutputStream(baos);
    		t = new TestSerialisation();
    		System.out.println("serialisation avec nouveau code: "+t);
    		flagVersionNouvelle=true;
    		oos.writeObject(t); // on simule l'écriture avec une vieille version
    		oos.flush();
    		oos.close();
    		System.out.println("désérialisation....");
    		t2 = (TestSerialisation) new ObjectInputStream(
    				new ByteArrayInputStream(
    						baos.toByteArray()
    						)
    				).readObject(); // on lit avec le code "générique"
    		System.out.println("désérialisé avec code générique: "+t2);
     
     
     
    	}
    	protected Object writeReplace() throws ObjectStreamException{
    		System.out.println("writeReplace main");
    		if (flagVersionNouvelle) // uniquement pour test, en pratique généralement on écrit dans la version la plus récente ;)
    			return new HolderV2(this);
    		else
    			return new HolderV1(this);
    	}
     
     
    }
    sortie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    serialisation avec ancien code de la nouvelle classe: blabla/blibli
    writeReplace main
    désérialisation....
    readResolve V1
    désérialisé suivant code générique: blabla/null
    serialisation avec nouveau code: blabla/blibli
    writeReplace main
    désérialisation....
    readResolve V2
    désérialisé avec code générique: blabla/blibli
    Ici tout est déjà fait, mais en pratique,

    Dans la version 1 tu aura que HolderV1, et aucune référénce à la String s2 puisque, on suppose, elle n'existe pas encore.

    Quand tu passera, disons à la version 2 de ton code, tu crée le nouvel Holder mais tu garde l'ancien par compatibilité. Le nouvel Holder aura aussi la String s2. Tu devra, accessoirement si nécessaire, modifier le readResolve de la version 1 pour gérer les champs qui étaient absents.

    Ainsi au final au lieu d'avoir un switch en fonction de la version, tu aura une classe différente qui gère la sérialsiation de chaque version.

  6. #6
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut
    Un grand merci pour ce bout de code qui va me faire gagner du temps

    A bientôt.
    @ bientôt...

    Salut & @+ sur 3W!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 05/08/2010, 11h41
  2. Réponses: 3
    Dernier message: 24/08/2009, 08h59
  3. Réponses: 9
    Dernier message: 02/03/2005, 22h46
  4. [version] Requete Update avec différentes versions de mySQL
    Par regbegpower dans le forum Requêtes
    Réponses: 2
    Dernier message: 26/01/2004, 17h19
  5. Appli devant tourner sous différentes versions de Windows?
    Par AnneOlga dans le forum C++Builder
    Réponses: 4
    Dernier message: 12/11/2003, 10h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo