[java] Qu'est-ce qu'un serialVersionUID et pourquoi devrais-je l'utiliser?



Answers

Si vous êtes en sérialisation juste parce que vous devez sérialiser pour l'implémentation (qui se soucie si vous sérialiser pour une HTTPSession, par exemple ... si elle est stockée ou non, vous ne vous souciez probablement pas de désérialiser un objet de formulaire) , alors vous pouvez ignorer cela.

Si vous utilisez réellement la sérialisation, cela n'a d'importance que si vous envisagez de stocker et de récupérer des objets directement à l'aide de la sérialisation. Le serialVersionUID représente votre version de classe, et vous devez l'incrémenter si la version actuelle de votre classe n'est pas rétrocompatible avec sa version précédente.

La plupart du temps, vous n'utiliserez probablement pas la sérialisation directement. Si c'est le cas, générez un UID sérialisable par défaut en cliquant sur l'option de correction rapide et ne vous inquiétez pas.

Question

Eclipse émet des avertissements lorsqu'un serialVersionUID est manquant.

La classe sérialisable Foo ne déclare pas un champ final serialVersionUID statique de type long

Qu'est-ce que serialVersionUID et pourquoi est-ce important? Veuillez montrer un exemple où serialVersionUID manquante causera un problème.




Qu'est-ce qu'un serialVersionUID et pourquoi devrais-je l'utiliser?

SerialVersionUID est un identificateur unique pour chaque classe, JVM utilise pour comparer les versions de la classe en s'assurant que la même classe a été utilisée pendant le chargement de la sérialisation pendant la désérialisation.

En spécifier un donne plus de contrôle, bien que JVM en génère un si vous ne le spécifiez pas. La valeur générée peut différer entre différents compilateurs. De plus, vous voulez parfois, pour une raison ou une autre, interdire la désérialisation des anciens objets sérialisés [ backward incompatibility ], et dans ce cas il vous suffit de changer le serialVersionUID.

Les docs Java disent :

"Le calcul serialVersionUID par défaut est très sensible aux détails de classe qui peuvent varier en fonction des implémentations du compilateur, et peut donc entraîner des InvalidClassExceptions inattendues lors de la désérialisation".

Vous devez déclarer serialVersionUID car cela nous donne plus de contrôle .

Cet article a quelques bons points sur le sujet.




Si vous obtenez cet avertissement sur une classe que vous ne pensez jamais à la sérialisation, et que vous ne vous êtes pas déclarés implements Serializable , c'est souvent parce que vous avez hérité d'une superclasse, qui implémente Serializable. Souvent, il serait préférable de déléguer à un tel objet au lieu d'utiliser l'héritage.

Donc, au lieu de

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

faire

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

et dans les méthodes appropriées, appelez myList.foo() au lieu de this.foo() (ou super.foo() ). (Cela ne convient pas dans tous les cas, mais encore assez souvent.)

Je vois souvent des gens étendre JFrame ou autre, alors qu'ils ont seulement besoin de déléguer à cela. (Cela facilite également l'auto-complétion dans un IDE, puisque JFrame a des centaines de méthodes, dont vous n'avez pas besoin quand vous voulez appeler vos personnalisées sur votre classe.)

Un cas où l'avertissement (ou serialVersionUID) est inévitable est lorsque vous étendez à partir de AbstractAction, normalement dans une classe anonyme, en ajoutant uniquement la méthode actionPerformed. Je pense qu'il ne devrait pas y avoir d'avertissement dans ce cas (puisque vous ne pouvez normalement pas sérialiser et désérialiser de telles classes anonymes de différentes versions de votre classe), mais je ne sais pas comment le compilateur pourrait le reconnaître.




Ne vous embêtez pas, le calcul par défaut est vraiment bon et suffisant pour 99,9999% des cas. Et si vous rencontrez des problèmes, vous pouvez - comme déjà indiqué - introduire les UID en tant que besoin d'arrise (ce qui est hautement improbable)




Vous pouvez demander à Eclipse d'ignorer ces avertissements serialVersionUID:

Fenêtre> Préférences> Java> Compilateur> Erreurs / avertissements> Problèmes de programmation potentiels

Au cas où vous ne le sauriez pas, il y a beaucoup d'autres avertissements que vous pouvez activer dans cette section (ou même dont certains sont signalés comme des erreurs), beaucoup sont très utiles:

  • Problèmes potentiels de programmation: Affectation booléenne accidentelle possible
  • Problèmes de programmation potentiels: Accès au pointeur nul
  • Code inutile: La variable locale n'est jamais lue
  • Code inutile: vérification null redondante
  • Code inutile: Cast inutile ou 'instanceof'

et beaucoup plus.




SerialVersionUID is used for version control of object. you can specify serialVersionUID in your class file also. Consequence of not specifying serialVersionUID is that when you add or modify any field in class then already serialized class will not be able to recover because serialVersionUID generated for new class and for old serialized object will be different. Java serialization process relies on correct serialVersionUID for recovering state of serialized object and throws java.io.InvalidClassException in case of serialVersionUID mismatch

Read more: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ




This question is very well documented in Effective Java by Joshua Bloch. A very good book and a must read. I will outline some of the reasons below :

The serialization runtime comes up with a number called Serial version for each serializable class. This number is called serialVersionUID. Now there is some Math behind this number and it comes out based on the fields/methods that are defined in the class. For the same class the same version is generated every time. This number is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException.

If the class is serializable you can also declare your own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long. Most IDE's like Eclipse help you generate that long string.




Les données de champ représentent certaines informations stockées dans la classe. La classe implémente l'interface Serializable , donc Eclipse offre automatiquement de déclarer le champ serialVersionUID . Commençons par la valeur 1 définie ici.

Si vous ne voulez pas que cet avertissement arrive, utilisez ceci:

@SuppressWarnings("serial")



Why use SerialVersionUID inside Serializable class in Java?

During serialization , Java runtime creates a version number for a class, so that it can de-serialize it later. This version number is known as SerialVersionUID in Java.

SerialVersionUID is used to version serialized data. You can only de-serialize a class if it's SerialVersionUID matches with the serialized instance. When we don't declare SerialVersionUID in our class, Java runtime generates it for us but its not recommended. It's recommended to declare SerialVersionUID as private static final long variable to avoid default mechanism.

When you declare a class as Serializable by implementing marker interface java.io.Serializable , Java runtime persist instance of that class into disk by using default Serialization mechanism, provided you have not customized the process using Externalizable interface.

see also Why use SerialVersionUID inside Serializable class in Java

Code : javassist.SerialVersionUID




Comme pour un exemple où le serialVersionUID manquant pourrait causer un problème:

Je travaille sur cette application Java EE composée d'un module Web qui utilise un module EJB . Le module Web appelle le module EJB distance et transmet un POJO qui implémente Serializable en tant qu'argument.

POJO's classe de ce POJO's été empaquetée dans le jar d'EJB et dans son propre jar dans le WEB-INF / lib du module web. Ils sont en fait de la même classe, mais quand j'emballe le module EJB, je déballe le pot de ce POJO pour l'empaqueter avec le module EJB.

L'appel à l' EJB échouait avec l'exception ci-dessous parce que je n'avais pas déclaré son serialVersionUID :

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52





Links