Comprendre le serialVersionUID
Si vous avez déjà implémenté l'interfaceSerializable, vous devez rencontrer ce message d'avertissement
The serializable class xxx does not declare a static final serialVersionUID field of type long
Alors… qu'est-ce que serialVersionUID?
Le serialVersionUID est utilisé comme contrôle de version dans une classe Serializable. Si vous ne déclarez pas explicitement un serialVersionUID, JVM le fera automatiquement pour vous, en fonction de divers aspects de votre classe Serializable, comme décrit dans lesJava™ Object Serialization Specification.
1. Exemple SerialVersionUID
L'instruction ci-dessus est un peu difficile à comprendre au début (du moins je l'ai fait), commençons par un exemple pour comprendre comment la classe Serializable utilise SerialVersionUID pour implémenter le contrôle de version.
1.1 Address.java
Une classe sérialisable avec un serialVersionUID de 1L.
import java.io.Serializable; public class Address implements Serializable{ private static final long serialVersionUID = 1L; String street; String country; public void setStreet(String street){ this.street = street; } public void setCountry(String country){ this.country = country; } public String getStreet(){ return this.street; } public String getCountry(){ return this.country; } @Override public String toString() { return new StringBuffer(" Street : ") .append(this.street) .append(" Country : ") .append(this.country).toString(); } }
1.2 WriteObject.java
Une classe simple pour écrire / sérialiser l'objet Address dans un fichier - «c: \ address.ser».
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class WriteObject{ public static void main (String args[]) { Address address = new Address(); address.setStreet("wall street"); address.setCountry("united states"); try{ FileOutputStream fout = new FileOutputStream("c:\\address.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(address); oos.close(); System.out.println("Done"); }catch(Exception ex){ ex.printStackTrace(); } } }
1.3 ReadObject.java
Une classe simple pour lire / désérialiser l'objet Address à partir du fichier - «c: \ address.ser».
import java.io.FileInputStream; import java.io.ObjectInputStream; public class ReadObject{ public static void main (String args[]) { Address address; try{ FileInputStream fin = new FileInputStream("c:\\address.ser"); ObjectInputStream ois = new ObjectInputStream(fin); address = (Address) ois.readObject(); ois.close(); System.out.println(address); }catch(Exception ex){ ex.printStackTrace(); } } }
2. Essai
Laissez faire quelques tests pour démontrer l'utilisation de serialVersionUID.
2.1 Same serialVersionUID
Même serialVersionUID, il n'y a aucun problème pendant le processus de désérialisation
javac Address.java javac WriteObject.java javac ReadObject.java java WriteObject java ReadObject Street : wall street Country : united states
2.2 Different serialVersionUID
Dans Address.java,change the serialVersionUID to 2L (c'était 1L), et compilez-le à nouveau.
javac Address.java java ReadObject java.io.InvalidClassException: Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 ... at ReadObject.main(ReadObject.java:14)
Le «InvalidClassException
» augmentera, car vous écrivez une classe de sérialisation avecserialVersionUID “1L” mais essayez de la récupérer avec la classe de sérialisation mise à jour,serialVersionUID “2L”.
Le serialVersionUID doit correspondre pendant le processus de sérialisation et de désérialisation.
When should update your serialVersionUID?
Lorsque votre classe de sérialisation est mise à jour avec des modifications de type Java incompatibles vers une classe sérialisable, vous devez mettre à jour votre serialVersionUID.
Pour plus de détails sur les changements de type Java compatibles et incompatibles vers une classe sérialisable, consultez lesJava Object Serialization Specification.
3. Quel est le problème avec le serialVersionUID par défaut?
Si aucun serialVersionUID n'est déclaré, JVM utilisera son propre algorithme pour générer un SerialVersionUID par défaut, vous pouvez vérifier l'algorithmehere.
The default serialVersionUID computation is highly sensitive to class details and may vary from different JVM implementation et provoquent des InvalidClassExceptions inattendues pendant le processus de désérialisation.
3.1 Client / Server environment
- Le client utilise la JVM de SUN sous Windows.
- Le serveur utilise JRockit sous Linux.
Le client envoie une classe sérialisable avec serialVersionUID généré par défaut (par exemple 123L) au serveur via socket, le serveur peut générer un serialVersionUID différent (par exemple 124L) pendant le processus de désérialisation, et déclenche une InvalidClassExceptions inattendue.
3.2 File / Database environment
- L'application n ° 1 utilise la JVM de SUN sous Windows.
- L'application n ° 2 utilise JRockit sous Linux.
La sérialisation a permis d'enregistrer dans un fichier ou une base de données. L'application n ° 1 stocke une classe sérialisable dans la base de données par défaut serialVersionUID généré (par exemple 123L), tandis que l'application n ° 2 peut générer un serialVersionUID différent (par exemple 124L) pendant le processus de désérialisation, et déclencher une InvalidClassExceptions inattendue.
Vous pouvez vérifier ici lesList of the JVM implementation.
4. Comment générer serialVersionUID
Vous pouvez utiliser JDK «serialver
» ou Eclipse IDE pour générer automatiquement serialVersionUID,see detail.
Conclusion
SUN est fortement recommandé aux développeurs de déclarer le serialVersionUID afin d'éviter les différents problèmes JVM répertoriés ci-dessus, mais je vous recommande plutôt de comprendre ce qu'est la sérialisation, comment serialVersionUID implémente le contrôle de version et pourquoi votre classe doit utiliser la sérialisation. Comprendre le concept serialVersionUID est meilleur que les yeux bandés à toute recommandation.
Références
-
http://java.sun.com/javase/6/docs/platform/serialization/spec/class.html#4100
-
http://stackoverflow.com/questions/419796/explicit-serialversionuid-considered-harmful
-
http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-control.html?page=1
-
http://www.java-forums.org/new-java/8196-serialversionuid.html