web-dev-qa-db-fra.com

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

Eclipse émet des avertissements quand il manque une serialVersionUID

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

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

2664
ashokgelal

Les docs pour Java.io.Serializable sont probablement une explication aussi bonne que celle que vous obtiendrez:

Le moteur d’exécution de la sérialisation associe à chaque classe sérialisable un numéro de version, appelé serialVersionUID, utilisé lors de la désérialisation pour vérifier que l’expéditeur et le destinataire d’un objet sérialisé ont chargé pour cet objet des classes compatibles avec la sérialisation. Si le destinataire a chargé une classe pour l'objet dont la variable serialVersionUID est différente de celle de la classe de l'expéditeur correspondante, la désérialisation aboutira à un InvalidClassException . Une classe sérialisable peut déclarer sa propre serialVersionUID explicitement en déclarant un champ nommé serialVersionUID qui doit être statique, final et de type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Si une classe sérialisable ne déclare pas explicitement une serialVersionUID, l'exécution de la sérialisation calculera alors une valeur par défaut serialVersionUID pour cette classe en fonction de divers aspects de la classe, comme décrit dans la spécification de sérialisation d'objet Java (TM). Cependant, il est fortement recommandé que toutes les classes sérialisables déclarent explicitement les valeurs serialVersionUID, car le calcul par défaut serialVersionUID est très sensible aux détails de classe qui peuvent varier en fonction de l'implémentation du compilateur et peuvent donc entraîner une InvalidClassExceptions inattendue lors de la désérialisation. Par conséquent, pour garantir une valeur serialVersionUID cohérente à travers différentes implémentations du compilateur Java, une classe sérialisable doit déclarer une valeur serialVersionUID explicite. Il est également fortement recommandé que les déclarations serialVersionUID explicites utilisent le modificateur private si possible, car elles ne s’appliquent qu’aux champs de classe serialVersionUID qui déclarent immédiatement ne sont pas utiles en tant que membres hérités.

2039
Jon Skeet

Si vous sérialisez simplement parce que vous devez sérialiser pour l'implémentation (qui se soucie de savoir si vous sérialisez une HTTPSession, par exemple ... si elle est stockée ou non, vous ne vous souciez probablement pas de de-serializing d'un objet de formulaire), vous pouvez l'ignorer.

Si vous utilisez réellement la sérialisation, le fait de stocker et de récupérer des objets directement à l'aide de la sérialisation n'a plus d'importance. La serialVersionUID représente la version de votre classe. 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 directement la sérialisation. Si tel est le cas, générez une SerialVersionUID par défaut en cliquant sur l'option de réparation rapide et ne vous inquiétez pas.

431
MetroidFan2002

Je ne peux pas rater l'occasion de brancher le livre de Josh Bloch Effective Java (2nd Edition). Le chapitre 11 est une ressource indispensable sur la sérialisation Java.

Pour Josh, l'UID généré automatiquement est généré en fonction d'un nom de classe, des interfaces implémentées et de tous les membres publics et protégés. Changer n'importe lequel de ceux-ci changera la serialVersionUID. Par conséquent, vous n'avez pas besoin de les manipuler uniquement si vous êtes certain qu'aucune version de la classe ne sera jamais sérialisée (à travers des processus ou extraite du stockage ultérieurement).

Si vous les ignorez pour l'instant et trouvez plus tard que vous devez modifier la classe tout en maintenant la compatibilité avec l'ancienne version de la classe, vous pouvez utiliser l'outil JDK serialver pour générer la serialVersionUID sur le old class et le définir explicitement sur la nouvelle classe. (En fonction de vos modifications, vous devrez peut-être également implémenter une sérialisation personnalisée en ajoutant des méthodes writeObject et readObject - voir Serializable javadoc ou au chapitre 11 susmentionné.)

279
Scott Bale

Vous pouvez indiquer à 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 en signaler quelques-uns comme des erreurs), beaucoup sont très utiles:

  • Problèmes de programmation potentiels: affectation booléenne accidentelle possible
  • Problèmes de programmation potentiels: Accès nul au pointeur
  • Code inutile: la variable locale n'est jamais lue
  • Code inutile: contrôle nul redondant
  • Code inutile: transtypage inutile ou 'instanceof'

et beaucoup plus.

126
matt b

serialVersionUID facilite la gestion des versions des données sérialisées. Sa valeur est stockée avec les données lors de la sérialisation. Lors de la désérialisation, la même version est vérifiée pour voir comment les données sérialisées correspondent au code actuel. 

Si vous souhaitez mettre à jour vos données, vous commencez normalement par une serialVersionUID de 0, et vous la remplacez à chaque modification structurelle de votre classe, ce qui modifie les données sérialisées (ajout ou suppression de champs non transitoires). 

Le mécanisme de désérialisation intégré (in.defaultReadObject()) refusera de désérialiser à partir d'anciennes versions des données. Mais si vous le souhaitez, vous pouvez définir votre propre fonction readObject () - qui peut relire d’anciennes données. Ce code personnalisé peut ensuite vérifier la variable serialVersionUID afin de connaître la version dans laquelle se trouvent les données et décider de la manière de la désérialiser. Cette technique de contrôle de version est utile si vous stockez des données sérialisées qui survivent à plusieurs versions de votre code.

Mais stocker des données sérialisées sur une période aussi longue n'est pas très courant. Il est beaucoup plus courant d'utiliser le mécanisme de sérialisation pour écrire temporairement des données dans un cache, par exemple, ou pour les envoyer sur le réseau à un autre programme doté de la même version des parties pertinentes de la base de code. 

Dans ce cas, la compatibilité avec les versions antérieures ne vous intéresse pas. Vous devez uniquement vous assurer que les bases de code qui communiquent ont effectivement les mêmes versions des classes pertinentes. Afin de faciliter une telle vérification, vous devez conserver la serialVersionUID comme avant et ne pas oublier de le mettre à jour lorsque vous modifiez vos classes. 

Si vous oubliez de mettre à jour le champ, vous pouvez vous retrouver avec deux versions différentes d'une classe avec une structure différente mais avec la même serialVersionUID. Si cela se produit, le mécanisme par défaut (in.defaultReadObject()) ne détectera aucune différence et tentera de désérialiser les données incompatibles. Vous pouvez maintenant vous retrouver avec une erreur d’exécution cryptique ou un échec silencieux (champs nuls). Ces types d'erreurs peuvent être difficiles à trouver.

Donc, pour aider ce cas d'utilisation, la plate-forme Java vous propose de ne pas définir manuellement la variable serialVersionUID. Au lieu de cela, un hachage de la structure de classe sera généré lors de la compilation et utilisé comme id. Grâce à ce mécanisme, vous ne disposerez jamais de structures de classe différentes avec le même identifiant. Ainsi, vous n'obtiendrez pas les erreurs de sérialisation d'exécution difficiles à tracer mentionnées ci-dessus.

Mais il y a un revers à la stratégie d'identification générée automatiquement. À savoir que les identifiants générés pour la même classe peuvent différer entre les compilateurs (comme mentionné par Jon Skeet ci-dessus). Donc, si vous communiquez des données sérialisées entre du code compilé avec différents compilateurs, il est néanmoins recommandé de gérer les identifiants manuellement. 

Et si vous êtes rétrocompatible avec vos données, comme dans le premier cas d'utilisation mentionné, vous souhaiterez probablement également conserver l'identifiant vous-même. Ceci afin d’obtenir des identifiants lisibles et d’avoir un meilleur contrôle sur quand et comment ils changent.

102

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

SerialVersionUID est un identifiant unique pour chaque classe. JVM l'utilise pour comparer les versions de la classe en s'assurant que la même classe a été utilisée lors de la sérialisation chargée lors de la désérialisation.

La spécification d'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, parfois, vous voulez simplement, pour une raison quelconque, interdire la désérialisation des anciens objets sérialisés [backward incompatibility], et dans ce cas, il vous suffit de modifier le serialVersionUID. 

Les javadocs pour Serializable say:

le calcul par défaut serialVersionUID est très sensible à la classe des détails qui peuvent varier en fonction de l’implémentation du compilateur et peuvent Il en résulte des valeurs InvalidClassExceptions inattendues pendant désérialisation.

Par conséquent, vous devez déclarer serialVersionUID car cela nous donne plus de contrôle.

Cet article a quelques bons points sur le sujet.

66
Thalaivar

La question initiale demandait «pourquoi est-ce important» et un «exemple» où ce Serial Version ID serait utile. Eh bien j'en ai trouvé un.

Supposons que vous créez une classe Car, que vous l'instanciez et que vous l'écriviez dans un flux d'objet. L'objet voiture aplati reste dans le système de fichiers pendant un certain temps. En attendant, si la classe Car est modifiée en ajoutant un nouveau champ. Plus tard, lorsque vous essayez de lire (c'est-à-dire de désérialiser) l'objet Car aplati, vous obtenez le Java.io.InvalidClassException - car toutes les classes sérialisables reçoivent automatiquement un identifiant unique. Cette exception est levée lorsque l'identifiant de la classe n'est pas égal à l'identifiant de l'objet aplati. Si vous y réfléchissez vraiment, l'exception est levée à cause de l'ajout du nouveau champ. Vous pouvez éviter cette exception en contrôlant vous-même la gestion des versions en déclarant un serialVersionUID explicite. Déclarer explicitement votre serialVersionUID (car il n’est pas nécessaire de le calculer) présente également un petit avantage en termes de performances. Il est donc recommandé d’ajouter votre propre serialVersionUID à vos classes Serializable dès que vous les créez, comme indiqué ci-dessous:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}
48
Rupesh

Si vous n'avez jamais besoin de sérialiser vos objets dans un tableau d'octets et de les envoyer/les stocker, vous n'avez pas à vous en préoccuper. Si vous le faites, vous devez alors considérer votre serialVersionUID car le désérialiseur de l'objet le fera correspondre à la version de l'objet de son chargeur de classes. En savoir plus à ce sujet dans la spécification du langage Java.

34
eishay

Si vous obtenez cet avertissement sur une classe pour laquelle vous ne pensez jamais à la sérialisation et que vous ne vous êtes pas déclarée 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 plutôt que 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 personnes rallonger JFrame ou autre, alors qu’elles n’ont qu’à déléguer à cela. (Cela facilite également la saisie automatique dans un IDE, car JFrame a des centaines de méthodes, dont vous n'avez pas besoin lorsque vous souhaitez appeler vos méthodes personnalisées dans votre classe.)

Dans certains cas, l'avertissement (ou le serialVersionUID) est inévitable 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 normalement vous ne pouvez pas sérieusement sérialiser et désérialiser de telles classes anonymes sur différentes versions de votre classe), mais je ne sais pas comment le compilateur pourrait le reconnaître.

33
Paŭlo Ebermann

Pour comprendre la signification du champ serialVersionUID, il convient de comprendre le fonctionnement de la sérialisation/désérialisation.

Lorsqu'un objet de classe Serializable est sérialisé, Java Runtime associe un numéro de version série (appelé en tant que serialVersionUID) à cet objet sérialisé. Au moment où vous désérialisez cet objet sérialisé, Java Runtime fait correspondre le serialVersionUID de l'objet sérialisé avec le serialVersionUID de la classe. Si les deux sont égaux, alors seul le processus de désérialisation est poursuivi, sinon l'instruction lève InvalidClassException.

Nous concluons donc que pour réussir le processus de sérialisation/désérialisation, le serialVersionUID de l'objet sérialisé doit être équivalent au serialVersionUID de la classe. Si le programmeur spécifie explicitement la valeur serialVersionUID dans le programme, la même valeur sera associée à l'objet sérialisé et à la classe, quelle que soit la plate-forme de sérialisation et de désérialisation (par exemple, la sérialisation peut être effectuée sur une plate-forme comme Windows à l'aide de MS JVM et Deserialization peuvent se trouver sur différentes plates-formes Linux utilisant Zing JVM).

Toutefois, si le programmeur ne spécifie pas le paramètre serialVersionUID, alors que Serialization\DeSerialization n’importe quel objet, le moteur d’exécution Java utilise son propre algorithme pour le calculer. Cet algorithme de calcul serialVersionUID varie d'un JRE à un autre. Il est également possible que l'environnement dans lequel l'objet est sérialisé utilise un seul JRE (ex: Sun JVM) et que l'environnement dans lequel la désérialisation se produit utilise Linux Jvm (zing). Dans de tels cas, serialVersionUID associé à un objet sérialisé sera différent du serialVersionUID de la classe calculé dans l'environnement de désérialisation. À son tour, la désérialisation ne sera pas réussie. Donc, pour éviter de telles situations/problèmes, le programmeur doit toujours spécifier serialVersionUID de la classe Serializable.

22
Nitesh Soni

En ce qui concerne un exemple où le serialVersionUID manquant peut causer un problème:

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

Cette classe POJO's a été intégrée dans le fichier jar EJB et dans son propre fichier jar dans le fichier WEB-INF/lib du module Web. Ils appartiennent en fait à la même classe, mais lorsque je compresse le module EJB, je décompresse le fichier jar de ce POJO pour le compresser avec le module EJB.

L'appel à la EJB a échoué avec l'exception ci-dessous car je n'avais pas déclaré sa 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
18
Henrique Ordine

Ne vous embêtez pas, le calcul par défaut est très bon et suffit dans 99,9999% des cas. Et si vous rencontrez des problèmes, vous pouvez - comme déjà indiqué - introduire les UID comme une nécessité (ce qui est très peu probable)

18
grand johnson

Je dois d'abord expliquer la sérialisation.
Sérialisation permet de convertir l'objet en flux afin de l'envoyer sur le réseau OR Sauvegarder dans le fichier OR sauvegardé dans la base de données pour une utilisation au format lettre. 

Il existe des règles pour la sérialisation

  • Un objet n'est sérialisable que si sa classe ou sa super-classe implémente l'interface Serializable

  • Un objet est sérialisable (implémente lui-même l'interface Serializable) même si sa super-classe ne l'est pas. Cependant, la première super-classe de la hiérarchie de la classe sérialisable, qui n'implémente pas l'interface Serializable, DOIT avoir un constructeur no-arg. Si cela est violé, readObject () produira une exception Java.io.InvalidClassException lors de l'exécution

  • Tous les types primitifs sont sérialisables.

  • Les champs transitoires (avec modificateur transitoire) ne sont PAS sérialisés (c.-à-d. Qu'ils ne sont ni sauvegardés ni restaurés). Une classe qui implémente Serializable doit marquer les champs transitoires des classes qui ne prennent pas en charge la sérialisation (par exemple, un flux de fichiers).

  • Les champs statiques (avec modificateur statique) ne sont pas sérialisés.

Lorsque l'objet est sérialisé, Java Runtime associe le numéro de version série appelé serialVersionID. 

Où nous avons besoin de serialVersionID:Pendant la désérialisation, vérifier que l'expéditeur et le destinataire sont compatibles en ce qui concerne la sérialisation. Si le destinataire a chargé la classe avec un autre serialVersionID, la désérialisation se terminera par InvalidClassCastException .
Une classe sérialisable peut déclarer explicitement son propre serialVersionUID en déclarant un champ nommé «serialVersionUID» qui doit être statique, final et de type long :.

Essayons cela avec un exemple.

import Java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Créer un objet sérialiser 

import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializ l'objet 

import Java.io.FileInputStream;
import Java.io.IOException;
import Java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

REMARQUE: modifiez maintenant le serialVersionUID de la classe Employee et enregistrez: 

private static final long serialVersionUID = **4L**;

Et exécutez la classe Reader. Ne pas exécuter la classe Writer et vous obtiendrez une exception. 

Exception in thread "main" Java.io.InvalidClassException: 
com.jagdish.vala.Java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at Java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.Java:616)
at Java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.Java:1623)
at Java.io.ObjectInputStream.readClassDesc(ObjectInputStream.Java:1518)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1774)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1351)
at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:371)
at com.krishantha.sample.Java.serialVersion.Reader.main(Reader.Java:14)
16
JegsVala

J'utilise généralement serialVersionUID dans un contexte: lorsque je sais qu'il quittera le contexte de la machine virtuelle Java. 

Je le saurais si je utilisais ObjectInputStream et ObjectOutputStream pour mon application ou si je connaissais une bibliothèque/structure que j'utiliserais l'utiliserait. SerialVersionID garantit que différentes machines virtuelles Java de versions différentes ou que différents fournisseurs interagissent correctement ou si elles sont stockées et extraites en dehors de la VM, par exemple HttpSession, les données de session peuvent rester même pendant le redémarrage et la mise à niveau du serveur d'applications.

Pour tous les autres cas, j'utilise 

@SuppressWarnings("serial")

puisque la plupart du temps, la variable serialVersionUID par défaut est suffisante. Ceci inclut Exception, HttpServlet.

15

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

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

@SuppressWarnings("serial")
14
Mukti

SerialVersionUID est utilisé pour le contrôle de version d'un objet. vous pouvez également spécifier serialVersionUID dans votre fichier de classe. La conséquence de ne pas spécifier serialVersionUID est que, lorsque vous ajoutez ou modifiez un champ de la classe, la classe déjà sérialisée ne pourra pas être récupérée car serialVersionUID généré pour la nouvelle classe et pour l'ancien objet sérialisé sera différent. Le processus de sérialisation Java repose sur le nom correct de serialVersionUID pour la récupération de l'état d'un objet sérialisé et lève l'exception Java.io.InvalidClassException en cas de non concordance entre serialVersionUID.

En savoir plus: http://javarevisited.blogspot.com/2011/04/top-10-Java-serialization-interview.html#ixzz3VQxnpOPZ

11
Neethu

Ce serait bien si CheckStyle pouvait vérifier que le serialVersionUID d’une classe qui implémentait Serializable avait une bonne valeur, c’est-à-dire qu’il correspond à ce que le générateur d’identificateurs de version série produirait. Par exemple, si vous avez un projet avec de nombreux DTO sérialisables, n'oubliez pas de supprimer le serialVersionUID existant et de le régénérer est une tâche ardue. À l'heure actuelle, le seul moyen (à ma connaissance) de le vérifier est de régénérer chaque classe et de le comparer le vieux. C'est très très douloureux.

10
David Wright

Pourquoi utiliser SerialVersionUID dans la Serializable classe en Java?

Au cours de serialization, le moteur d’exécution Java crée un numéro de version pour une classe, afin de pouvoir la désérialiser ultérieurement. Ce numéro de version est appelé SerialVersionUID en Java.

SerialVersionUID est utilisé pour la version des données sérialisées. Vous ne pouvez désérialiser une classe que si sa SerialVersionUID correspond à l'instance sérialisée. Lorsque nous ne déclarons pas SerialVersionUID dans notre classe, le runtime Java le génère pour nous, mais ce n'est pas recommandé. Il est recommandé de déclarer SerialVersionUID comme variable private static final long pour éviter le mécanisme par défaut. 

Lorsque vous déclarez une classe en tant que Serializable en implémentant l'interface de marqueur Java.io.Serializable, l'instance Java de cette classe conserve cette instance sur le disque à l'aide du mécanisme de sérialisation par défaut, à condition que vous n'ayez pas personnalisé le processus à l'aide de l'interface Externalizable.

voir aussi Pourquoi utiliser SerialVersionUID dans la classe Serializable en Java

Code: javassist.SerialVersionUID

9
roottraveller

Si vous souhaitez modifier un grand nombre de classes pour lesquelles aucun serialVersionUID n'a été défini tout en conservant la compatibilité avec les anciennes classes, des outils tels qu'IntelliJ Idea, Eclipse ne fonctionnent pas car ils génèrent des nombres aléatoires et ne fonctionnent pas sur plusieurs fichiers en une fois. Je viens le script bash suivant (je suis désolé pour les utilisateurs de Windows, envisagez d’acheter un Mac ou de le convertir sous Linux) pour résoudre facilement le problème de serialVersionUID:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/Java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.Java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    Perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

vous enregistrez le script this, dites add_serialVersionUID.sh ~/bin. Ensuite, vous l’exécutez dans le répertoire racine de votre projet Maven ou Gradle, comme suit:

add_serialVersionUID.sh < myJavaToAmend.lst

Ce fichier .lst inclut la liste des fichiers Java permettant d’ajouter le serialVersionUID au format suivant:

com/abc/ic/api/model/domain/item/BizOrderTransDO.Java
com/abc/ic/api/model/domain/item/CardPassFeature.Java
com/abc/ic/api/model/domain/item/CategoryFeature.Java
com/abc/ic/api/model/domain/item/GoodsFeature.Java
com/abc/ic/api/model/domain/item/ItemFeature.Java
com/abc/ic/api/model/domain/item/ItemPicUrls.Java
com/abc/ic/api/model/domain/item/ItemSkuDO.Java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.Java
com/abc/ic/api/model/domain/serve/ServeFeature.Java
com/abc/ic/api/model/param/depot/DepotItemDTO.Java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.Java
com/abc/ic/api/model/param/depot/InDepotDTO.Java
com/abc/ic/api/model/param/depot/OutDepotDTO.Java

Ce script utilise l'outil JDK serialVer sous le capot. Assurez-vous donc que votre $ Java_HOME/bin est dans le PATH.

7
schnell18

Cette question est très bien documentée dans Effective Java de Joshua Bloch. Un très bon livre et à lire absolument. Je vais exposer certaines des raisons ci-dessous:

Le runtime de sérialisation fournit un numéro appelé Version série pour chaque classe sérialisable. Ce numéro s'appelle serialVersionUID. Il y a maintenant un peu de math derrière ce nombre et il est basé sur les champs/méthodes définis dans la classe. Pour la même classe, la même version est générée à chaque fois. Ce numéro est utilisé lors de la désérialisation pour vérifier que l'expéditeur et le destinataire d'un objet sérialisé ont des classes chargées pour cet objet compatibles avec la sérialisation. Si le destinataire a chargé une classe pour l'objet dont l'ID de série est différent de celui de la classe de l'expéditeur correspondante, la désérialisation génère une exception InvalidClassException.

Si la classe est sérialisable, vous pouvez également déclarer explicitement votre propre serialVersionUID en déclarant un champ nommé "serialVersionUID" qui doit être statique, final et de type long. La plupart des IDE comme Eclipse vous aident à générer cette longue chaîne.

6
Geek

Chaque fois qu'un objet est sérialisé, l'objet est marqué d'un numéro d'identification de version pour la classe de cet objet. Cet ID est appelé serialVersionUID et il est calculé en fonction des informations relatives à la structure de classe. Supposons que vous ayez créé une classe Employee et que son identifiant de version soit n ° 333 (attribué par JVM). Maintenant, lorsque vous allez sérialiser l'objet de cette classe (objet Suppose Employee), JVM lui attribuera l'UID sous le numéro 333.

Considérons une situation - à l'avenir, vous devrez éditer ou changer votre classe et dans ce cas, lorsque vous la modifierez, JVM lui attribuera un nouvel UID (Suppose # 444) . Maintenant, lorsque vous essayez de désérialiser l'objet employé, La JVM comparera l'ID de version (n ° 333) de l'objet sérialisé (objet employé) avec celui de la classe, c'est-à-dire n ° 444 (car il a été modifié). Par comparaison, JVM trouvera que les deux UID de version sont différents et que, par conséquent, la désérialisation échouera . Par conséquent, si serialVersionID est défini pour chaque classe par le programmeur lui-même. Il en ira de même même si la classe évolue dans le futur. Par conséquent, JVM trouvera toujours que cette classe est compatible avec les objets sérialisés même si la classe a été modifiée. Pour plus d'informations, vous pouvez vous reporter au chapitre 14 de HEAD FIRST Java.

6
Er.Naved Ali

Une explication simple
1. Etes-vous en train de sérialiser des données? La sérialisation est en train d'écrire des données de classe dans un fichier/flux/etc. La désérialisation consiste à lire ces données dans une classe.
2. Avez-vous l’intention de passer à la production? Si vous testez quelque chose avec des données sans importance/fausses, ne vous inquiétez pas (sauf si vous testez directement la sérialisation).
3. S'agit-il de la première version? Si oui, définissez serialVersionUID=1L.
4. S'agit-il des deuxième, troisième, etc. versions prod? Maintenant, vous devez vous préoccuper de serialVersionUID, et devriez l'examiner en profondeur.

Fondamentalement, si vous ne mettez pas à jour la version correctement lorsque vous mettez à jour une classe que vous devez écrire/lire, vous obtiendrez une erreur lorsque vous essayez de lire des données anciennes.

1
gagarwa

Premièrement, pour répondre à votre question, lorsque nous ne déclarons pas SerialVersionUID dans notre classe, le runtime Java le génère pour nous, mais ce processus est sensible à de nombreuses métadonnées de classe, notamment le nombre de champs, le type de champs, le modificateur d'accès des champs, l'interface implémentée par classe, etc. Par conséquent, il est recommandé de le déclarer nous-mêmes et Eclipse vous en avertit.

Sérialisation: nous travaillons souvent avec des objets importants dont l'état (données dans les variables de l'objet) est si important que nous ne pouvons pas risquer de le perdre en raison de pannes d'alimentation/du système (ou) du réseau en cas d'envoi de l'état de l'objet à d'autres machine. La solution à ce problème est nommée "Persistance", ce qui signifie simplement la conservation (conservation/sauvegarde) des données. La sérialisation est l’un des nombreux moyens d’atteindre la persistance (en sauvegardant les données sur disque/mémoire). Lors de la sauvegarde de l'état de l'objet, il est important de créer une identité pour l'objet afin de pouvoir le relire correctement (désérialisation). Cette identification unique est l'ID est SerialVersionUID.

0
Shanks D Shiva

Pour décrire le récit long, ce champ permet de vérifier si les données sérialisées peuvent être désérialisées correctement. La sérialisation et la désérialisation sont souvent effectuées par différentes copies du programme - par exemple, le serveur convertit l'objet en chaîne et le client convertit la chaîne reçue en objet. Ce champ indique que les deux fonctionnent avec la même idée de ce qu'est cet objet. Ce champ est utile lorsque:

  • vous avez plusieurs copies différentes de votre programme à différents endroits (par exemple, 1 serveur et 100 clients). Si vous changez votre objet, changez votre numéro de version et oubliez d'en mettre à jour l'un de ces clients, il saura qu'il n'est pas capable de désérialiser

  • vous avez stocké vos données dans un fichier et vous essayez plus tard de l'ouvrir avec la version mise à jour de votre programme avec un objet modifié - vous saurez que ce fichier n'est pas compatible si vous conservez la version correcte

Quand est-ce important?

Le plus évident est que si vous ajoutez des champs à votre objet, les anciennes versions ne pourront pas les utiliser car elles ne contiennent pas ces champs dans leur structure d'objet.

Moins évident - Lorsque vous désérialisez un objet, les champs qui n'étaient pas présents dans chaîne seront conservés comme NULL. Si vous avez supprimé le champ de votre objet, les anciennes versions conserveront ce champ toujours all-NULL, ce qui peut entraîner un comportement incorrect si les anciennes versions s'appuient sur des données de ce champ (vous l'avez de toute façon créé pour quelque chose, pas seulement pour le plaisir :-))

Le moins évident: vous changez parfois l'idée que vous avez mise dans le sens d'un champ. Par exemple, quand vous avez 12 ans, vous voulez dire «vélo» sous «vélo», mais à 18 ans, vous voulez dire «moto» - si vos amis vous invitent à «faire du vélo à travers la ville» et que vous serez le seul venu à bicyclette, vous comprendrez à quel point il est important de garder le même sens dans tous les domaines :-)

0
Stanislav Orlov