Question

Eclipse émet des avertissements en cas d'absence d'un serialVersionUID .

  

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

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

Était-ce utile?

La solution

Les documents pour java.io.Serializable constitue probablement la meilleure explication que vous obtiendrez:

  

L'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é des classes pour cet objet compatible en ce qui concerne la sérialisation. Si le destinataire a chargé une classe pour l'objet dont le serialVersionUID est différent de celui de la classe de l'expéditeur correspondante, la désérialisation entraînera une    InvalidClassException . 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 :

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

Si une classe sérialisable ne déclare pas explicitement un 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 suit: décrit dans la spécification de sérialisation d’objet Java (TM). Cependant, il est vivement 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 des implémentations du compilateur, et peut donc entraîner des InvalidClassExceptions inattendus lors de la désérialisation. Par conséquent, pour garantir une valeur serialVersionUID cohérente dans 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 ces déclarations ne s'appliquent qu'aux champs à déclaration immédiate de la classe serialVersionUID en tant que membres hérités.

Autres conseils

Si vous êtes en train de sérialiser simplement parce que vous devez le faire pour des raisons d'implémentation (peu importe si vous sérialisez pour un HTTPSession , par exemple ... s'il est stocké ou non, vous ne le faites probablement pas. ne vous souciez pas de déssérialiser un objet de formulaire), vous pouvez alors l'ignorer.

Si vous utilisez réellement la sérialisation, le fait que vous envisagiez de stocker et de récupérer directement des objets à l'aide de la sérialisation n'a d'importance. Le 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 un SerialVersionUID par défaut en cliquant sur l'option de réparation rapide et ne vous inquiétez pas.

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

Par 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. Toute modification de l’une quelconque de ces façons changera le serialVersionUID . Vous n'avez donc 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 constatez ultérieurement 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 serialVersionUID sur la ancienne classe, et le définit explicitement sur la nouvelle classe. (En fonction de vos modifications, vous devrez peut-être également implémenter une sérialisation personnalisée en ajoutant les méthodes writeObject et readObject - voir Serializable javadoc ou le chapitre 11 susmentionné.)

Vous pouvez dire à 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 certains 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 d'autres.

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 un serialVersionUID de 0, et vous le repoussez à chaque modification structurelle apportée à 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 readObject () - fonction qui peut relire d'anciennes données. Ce code personnalisé peut ensuite vérifier le serialVersionUID afin de connaître la version dans laquelle se trouvent les données et décider de la manière de le 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.

Cependant, le stockage de 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 bien les mêmes versions des classes pertinentes. Afin de faciliter cette vérification, vous devez conserver serialVersionUID exactement comme avant et ne pas oublier de le mettre à jour lorsque vous modifiez vos classes.

Si vous oubliez de mettre à jour le champ, vous pourriez vous retrouver avec deux versions différentes d'une classe avec une structure différente mais avec le 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). Il est parfois difficile de trouver ces types d’erreurs.

Pour aider ce cas d'utilisation, la plate-forme Java vous propose de ne pas définir manuellement le 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 ne rencontrerez pas les problèmes de sérialisation d’exécution difficiles à retracer mentionnés ci-dessus.

La stratégie d’identification générée automatiquement présente toutefois un revers. À 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 le moment et la manière dont ils changent.

  

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

SerialVersionUID est un identificateur 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.

Si vous en spécifiez un, vous aurez 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 selon les compilateurs. De plus, vous souhaitez parfois, pour une raison quelconque, interdire la désérialisation des anciens objets sérialisés [ incompatibilité avec les versions antérieures ], et dans ce cas, il vous suffit de modifier le serialVersionUID.

Le javadocs pour Serializable dire :

  

le calcul serialVersionUID par défaut 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 InvalidClassException inattendues lors de   désérialisation.

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

Cet article contient de bons points sur le sujet.

La question initiale demandait "Pourquoi est-ce important" et "un exemple" où cet ID de version série serait utile. Et 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 l'objet java.io.InvalidClassException & # 8211; parce que 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. La déclaration explicite de votre serialVersionUID présente également un petit avantage en termes de performances (car elle ne doit pas être calculée). 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
}

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. Plus d'informations à ce sujet dans la spécification du langage Java.

Si vous recevez cet avertissement sur une classe que vous ne pensez jamais sérialiser et que vous ne vous êtes pas déclarée implémente Serializable , c’est souvent parce que vous avez hérité d’une superclasse, qui implémente Sérialisable. 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 reste assez souvent.)

Je vois souvent des personnes étendre JFrame ou une telle personne alors qu’elles n’ont vraiment besoin que de déléguer cette tâche. (Cela facilite également la saisie automatique dans un IDE, car JFrame propose des centaines de méthodes, ce dont vous n’avez pas besoin lorsque vous souhaitez appeler vos méthodes personnalisées dans votre classe.)

L'avertissement (ou le serialVersionUID) est inévitable lorsque vous étendez l'extension 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 (étant donné que vous ne pouvez normalement pas sérialiser et désérialiser de manière fiable de telles classes anonymes sur différentes versions de votre classe), mais je ne sais pas comment le compilateur pourrait le reconnaître.

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é 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 suivant est lancé, sinon une exception InvalidClassException est générée.

Nous concluons donc que pour que le processus de sérialisation / désérialisation aboutisse, 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 La machine virtuelle Java et la désérialisation peuvent se trouver sur différentes plateformes Linux utilisant la machine virtuelle Zing).

Mais si, au cas où serialVersionUID n'est pas spécifié par le programmeur, tout en effectuant une sérialisation \ désSérialisation d'un objet, l'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 (par exemple: 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 de serialVersionUID de la classe calculée 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.

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

Il existe certaines 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 ceci est violé, readObject () produira une exception java.io.InvalidClassException au moment de l'exécution

  • Tous les types primitifs sont sérialisables.

  • Les champs transitoires (avec modificateur transitoire) ne sont PAS sérialisés (c'est-à-dire non sauvegardés ou 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.

Quand 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 pour 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 serialVersionID différent, la désérialisation se terminera avec InvalidClassCastException .
 Une classe sérialisable peut déclarer explicitement son propre serialVersionUID en déclarant un champ nommé & # 8220; serialVersionUID & # 8221; qui doit être statique, final et de type long:.

Essayons ceci 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 de sérialisation

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 à présent 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)

Ne vous inquiétez pas, le calcul par défaut est vraiment 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 hautement improbable)

En ce qui concerne un exemple où le numéro de série manquant serialVersionUID peut être à l'origine d'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 un POJO qui implémente Serializable en tant qu'argument.

Cette classe POJO a été empaqueté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 l’emballer avec le module EJB.

L'appel à EJB a échoué avec l'exception ci-dessous car 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

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

Je le saurais si je devais utiliser ObjectInputStream et ObjectOutputStream pour mon application ou si je connaissais une bibliothèque / framework que j'utiliserais. SerialVersionID garantit que différentes machines virtuelles Java de versions différentes ou que différents fournisseurs interagiront correctement ou que, si elle est stockée et extraite en dehors de la machine virtuelle, par exemple HttpSession , les données de session peuvent rester même pendant le redémarrage et la mise à niveau de l'application. serveur.

Pour tous les autres cas, j'utilise

@SuppressWarnings("serial")

Depuis la plupart du temps, le serialVersionUID par défaut est suffisant. Cela inclut Exception , HttpServlet .

Les données de champ représentent certaines informations stockées dans la classe. Class implémente l'interface Serializable , donc 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")

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 serialVersionUID correct pour la récupération de l'état d'un objet sérialisé et émet une exception java.io.InvalidClassException en cas de non concordance serialVersionUID

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

Il serait bon que CheckStyle puisse vérifier que le serialVersionUID d’une classe qui implémente Serializable a une bonne valeur, c’est-à-dire qu’il correspond à ce que le générateur d’identificateurs de version série produira. Par exemple, si vous avez un projet avec beaucoup de DTO sérialisables, n'oubliez pas de supprimer le serialVersionUID existant et de le régénérer est une tâche difficile, et actuellement le seul moyen (à ma connaissance) de le vérifier consiste à régénérer pour chaque classe et à le comparer. le vieux. C'est très très douloureux.

Pourquoi utiliser SerialVersionUID dans la classe Serializable en Java?

Au cours de la sérialisation , le moteur d’exécution Java crée un numéro de version pour une classe afin qu’elle puisse 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 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 en tant que variable statique finale privée longue pour éviter le mécanisme par défaut.

Lorsque vous déclarez une classe comme Serializable en implémentant l'interface de marqueur java.io.Serializable , l'instance Java d'exécution persistante de cette classe sur disque utilise le mécanisme de sérialisation par défaut, à condition vous n'avez pas personnalisé le processus à l'aide de l'interface Externalizable .

voir aussi Pourquoi utiliser SerialVersionUID dans la classe Serializable en Java

Code: javassist.SerialVersionUID

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 de manière aléatoire. tas de fichiers en une seule fois. Je viens avec le script bash suivant (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 

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 de manière aléatoire. tas de fichiers en une seule fois. Je viens avec le script bash suivant (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:

add_serialVersionUID.sh < myJavaToAmend.lst

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, par exemple:

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 fichier .lst inclut la liste des fichiers Java pour ajouter le serialVersionUID au format suivant:

<*>

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

; 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, par exemple:

<*>

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

<*>

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

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 entraîne 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". cela doit être statique, final et de type long. La plupart des IDE comme Eclipse vous aident à générer cette longue chaîne.

Chaque fois qu'un objet est sérialisé, il porte un numéro d'identification de version pour la classe d'objet. Cet ID s'appelle serialVersionUID et il est calculé en fonction des informations sur la structure de classe. Supposons que vous ayez créé une classe Employee et que son identifiant de version soit n ° 333 (attribué par la machine virtuelle Java). Maintenant, lorsque vous sérialiserez l'objet de cette classe (objet Suppose Employee), la machine virtuelle Java lui attribuera l'UID sous la forme # 333.

Considérez une situation. À l'avenir, vous devrez éditer ou modifier votre classe. Dans ce cas, lorsque vous la modifierez, JVM lui attribuera un nouvel UID (Suppose # 444). Désormais, lorsque vous essayez de désérialiser l'objet employé, JVM comparera l'ID de version (n ° 333) de l'objet sérialisé (employé) avec celui de la classe i.e n ° 444 (car il a été modifié). En comparaison, JVM trouvera les deux UID de version différents et, par conséquent, la désérialisation échouera. Par conséquent, si serialVersionID pour chaque classe est défini 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 est modifiée. Pour plus d'informations, vous pouvez vous reporter au chapitre 14 de HEAD FIRST JAVA.

Une explication simple:

  1. sérialisez-vous les données?

    La sérialisation consiste à é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 tel est le cas, définissez serialVersionUID = 1L .

  4. S'agit-il de la deuxième, troisième, etc. version prod?

    Vous devez maintenant vous préoccuper de serialVersionUID et vous devriez l'examiner en détail.

En gros, 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 les anciennes données.

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 votre version correcte

Quand est-ce important?

Plus évident - si vous ajoutez des champs à votre objet, les versions antérieures ne pourront pas les utiliser car ils 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 la 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 mettez dans le sens d’un champ. Par exemple, lorsque vous avez 12 ans, vous voulez dire "vélo". sous "vélo", mais quand vous avez 18 ans, vous voulez dire "moto". - si vos amis vous invitent à " balade à vélo à travers la ville " et vous serez le seul à venir à bicyclette, vous comprendrez à quel point il est important de garder le même sens dans tous les domaines: -)

Tout d'abord, pour répondre à votre question, lorsque nous ne déclarons pas SerialVersionUID dans notre classe, l'exécution 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. , interface implémentée par la classe etc. Il est donc 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 tellement 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 à une autre machine. La solution à ce problème s'appelle "Persistence". ce qui signifie simplement conserver (conserver / sauvegarder) les 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top