3320 votes

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

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

La classe sérialisable Foo ne déclare pas de static final serialVersionUID de type long

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

4 votes

Trouvez une bonne pratique concernant serialversionUID ; dzone.com/articles/what-is-serialversionuid

2513voto

Jon Skeet Points 692016

Les documents relatifs à java.io.Serializable sont probablement la meilleure explication que vous puissiez obtenir :

Le runtime de sérialisation associe à chaque classe sérialisable un numéro de version, appelé un serialVersionUID qui est utilisé pendant la désérialisation pour vérifier que l'expéditeur et le récepteur d'un objet sérialisé ont chargé des classes pour cet objet qui sont compatibles avec la sérialisation. Si le récepteur a chargé une classe pour l'objet qui a une valeur de serialVersionUID que celle de la classe de l'expéditeur correspondant, alors la désérialisation donnera lieu à une 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 classe de type serialVersionUID alors le runtime de sérialisation calculera une valeur par défaut de l'option serialVersionUID pour cette classe en fonction de divers aspects de la classe, comme décrit dans la spécification de sérialisation des objets de Java(TM). Cependant, il est fortement recommandé que toutes les classes sérialisables déclarent explicitement serialVersionUID puisque les valeurs par défaut serialVersionUID est très sensible aux détails de la classe qui peuvent varier en fonction des implémentations du compilateur, et peut donc donner lieu à des résultats inattendus. InvalidClassExceptions pendant la désérialisation. Par conséquent, pour garantir une serialVersionUID à travers différentes implémentations du compilateur java, une classe sérialisable doit déclarer une valeur explicite serialVersionUID valeur. Il est également fortement conseillé d'utiliser des serialVersionUID utilisent le modificateur private lorsque cela est possible, car ces déclarations ne s'appliquent qu'à la classe qui les déclare immédiatement. serialVersionUID ne sont pas utiles en tant que membres hérités.

374 votes

Donc, ce que vous dites essentiellement, c'est que si un utilisateur ne comprend pas tout ce qui précède, il ne doit pas se soucier de la sérialisation ? Je crois que vous avez répondu au "comment" plutôt que d'expliquer le "pourquoi". Pour ma part, je ne comprends pas pourquoi je devrais me préoccuper de SerializableVersionUID.

397 votes

Le pourquoi est dans le deuxième paragraphe : si vous ne spécifiez pas explicitement serialVersionUID, une valeur est générée automatiquement - mais c'est fragile car cela dépend de l'implémentation du compilateur.

19 votes

Et pourquoi Eclipse me dit que j'ai besoin de "private static final long serialVersionUID = 1L ;" lorsque j'étend la classe Exception ?

506voto

MetroidFan2002 Points 11413

Si vous sérialisez juste parce que vous devez sérialiser pour le bien de l'implémentation (qui se soucie de sérialiser pour une HTTPSession par exemple... qu'il soit stocké ou non, vous ne vous souciez probablement pas de... de-serializing un objet de formulaire), alors vous pouvez ignorer ceci.

Elle n'a d'importance que si vous prévoyez de stocker et de récupérer des objets en utilisant directement la sérialisation. Le site serialVersionUID représente la version de votre 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 fichier SerialVersionUID en cliquant sur l'option de réparation rapide et ne vous inquiétez pas.

87 votes

Je dirais que si vous n'utilisez pas la sérialisation pour un stockage permanent, vous devriez utiliser @SuppressWarnings plutôt que d'ajouter une valeur. Cela encombre moins la classe et préserve l'aptitude du mécanisme serialVersionUID à vous protéger des modifications incompatibles.

28 votes

Je ne vois pas comment l'ajout d'une ligne (annotation @SuppressWarnings) par rapport à une autre ligne (id sérialisable) "encombre moins la classe". Et si vous n'utilisez pas la sérialisation pour un stockage permanent, pourquoi n'utiliseriez-vous pas simplement "1" ? Vous ne vous soucieriez pas de l'ID généré automatiquement dans ce cas de toute façon.

75 votes

@MetroidFan2002 : Je pense que le point de vue de @TomAnderson de serialVersionUID vous protégeant des changements incompatibles est valable. Utilisation de @SuppressWarnings documente mieux l'intention si vous ne souhaitez pas utiliser la classe pour un stockage permanent.

348voto

Scott Bale Points 4385

Je ne peux pas laisser passer l'occasion de présenter le livre de Josh Bloch. Java efficace (2ème édition). Le chapitre 11 est une ressource indispensable sur la sérialisation Java.

Selon Josh, l'UID généré automatiquement se base sur le nom d'une classe, les interfaces implémentées et tous les membres publics et protégés. Si l'on modifie l'un de ces éléments de quelque manière que ce soit, l'UID est modifié. serialVersionUID . Il n'est donc pas nécessaire de s'en préoccuper si vous êtes certain que plusieurs versions de la classe ne seront jamais sérialisées (que ce soit entre les processus ou à partir du stockage à un moment ultérieur).

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

39 votes

On pourrait donc utiliser SerializableVersionUID si l'on était préoccupé par la compatibilité avec les anciennes versions d'une classe ?

15 votes

En effet, si la version la plus récente change un membre public en membre protégé, l'identifiant SerializableVersionUID par défaut sera différent et provoquera une InvalidClassExceptions.

3 votes

Nom de la classe, interfaces implémentées, toutes les méthodes publiques et protégées, TOUTES les variables d'instance.

141voto

matt b Points 73770

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

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

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 faire signaler certains comme des erreurs), beaucoup sont très utiles :

  • Problèmes potentiels de programmation : Possibilité d'affectation booléenne accidentelle
  • Problèmes potentiels de programmation : Accès aux pointeurs nuls
  • Code inutile : La variable locale n'est jamais lue
  • Code inutile : Contrôle de nullité redondant
  • Un code inutile : Cast ou 'instanceof' inutile

et bien d'autres encore.

24 votes

Upvote mais seulement parce que l'affiche originale ne semble pas sérialiser quoi que ce soit. Si le posteur avait dit "je suis en train de sérialiser cette chose et ...", alors vous auriez obtenu un vote vers le bas au lieu de :P

4 votes

C'est vrai - je supposais que l'auteur de la question ne voulait simplement pas être prévenu.

15 votes

@Gardner -> d'accord ! Mais l'auteur de la question veut aussi savoir pourquoi il pourrait ne pas vouloir être averti.

123voto

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 voulez faire une version de vos données, vous commencez normalement par un fichier serialVersionUID de 0, et la modifier à chaque changement structurel de votre classe 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 les anciennes versions des données. Mais si vous le souhaitez, vous pouvez définir votre propre méthode de désérialisation. readObject() -Cette fonction permet de relire les anciennes données. Ce code personnalisé peut alors vérifier le serialVersionUID afin de savoir dans quelle version se trouvent les données et de décider comment les désérialiser. Cette technique de versionnage est utile si vous stockez des données sérialisées qui survivent à plusieurs versions de votre code.

Mais le stockage de données sérialisées pendant 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 par le réseau à un autre programme possédant la même version des parties concernées du code de base.

Dans ce cas, vous n'êtes pas intéressé par le maintien de la compatibilité ascendante. Vous voulez seulement vous assurer que les bases de code qui communiquent ont bien les mêmes versions des classes concernées. Afin de faciliter une telle vérification, vous devez maintenir la classe serialVersionUID comme avant et n'oubliez pas de le mettre à jour lorsque vous apportez des modifications à vos classes.

Si vous oubliez de mettre à jour le champ, vous risquez de 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 essaiera de désérialiser les données incompatibles. Vous risquez alors de vous retrouver avec une erreur d'exécution cryptique ou un échec silencieux (champs nuls). Ces types d'erreurs peuvent être difficiles à trouver.

Ainsi, pour faciliter ce cas d'utilisation, la plate-forme Java vous offre la possibilité de ne pas définir l'option serialVersionUID manuellement. Au lieu de cela, un hachage de la structure de la classe sera généré à la compilation et utilisé comme identifiant. Ce mécanisme permet de s'assurer que vous n'avez jamais de structures de classe différentes avec le même identifiant, et donc que vous n'aurez pas ces échecs de sérialisation à l'exécution difficiles à tracer mentionnés ci-dessus.

Mais il y a un revers à la stratégie de l'identifiant généré automatiquement. En effet, les identifiants générés pour une même classe peuvent différer d'un compilateur à l'autre (comme l'a mentionné Jon Skeet ci-dessus). Donc, si vous communiquez des données sérialisées entre du code compilé avec différents compilateurs, il est recommandé de maintenir les ids manuellement de toute façon.

Et si vous êtes rétrocompatible avec vos données, comme dans le premier cas d'utilisation mentionné, vous souhaitez probablement aussi maintenir 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 sont modifiés.

5 votes

L'ajout ou la suppression de champs non transitoires ne rend pas la classe incompatible avec la sérialisation. Il n'y a donc pas de raison de la faire sauter lors de tels changements.

4 votes

@EJP : Huh ? L'ajout de données modifie définitivement les données de sérialisation dans mon monde.

3 votes

@AlexanderTorstling Lisez ce que j'ai écrit. Je n'ai pas dit que cela ne "change pas les données de sérialisation". J'ai dit que cela "ne rend pas la classe incompatible avec la sérialisation". Ce n'est pas la même chose. Vous devez lire le chapitre Versioning de l'Object Serialization Specification.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X