J'ai créé client et serveur, puis ajouté une classe côté client à des fins de sérialisation, puis je suis simplement allé dans le dossier du client sur mon disque dur et copié-collé à l'emplacement correspondant du serveur, respectivement classname.class
et classname.Java
.
Cela fonctionnait bien sur mon propre ordinateur portable, mais lorsque je voulais continuer mon travail sur un autre système, lorsque j'ouvrais les dossiers de projets et que le client essayait de se connecter au serveur, le message d'erreur suivant apparaît:
Exception in thread "main" Java.io.InvalidClassException: projectname.clasname; local class incompatible: stream classdesc serialVersionUID = -6009442170907349114, local class serialVersionUID = 6529685098267757690
at Java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.Java:562)
at Java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.Java:1582)
at Java.io.ObjectInputStream.readClassDesc(ObjectInputStream.Java:1495)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1731)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)
Que se passe-t-il? Est-ce parce que j'ai exécuté le programme avec une version plus ancienne de l'EDI?
import Java.io.Serializable;
import Java.net.URL;
public class KeyAdr implements Serializable {
private static final long serialVersionUID = 6529685098267757690L;
public URL adr;
public String key;
}
Si une classe ne définit pas explicitement un private static final long serialVersionUID
dans le code, elle sera générée automatiquement et rien ne garantit que différentes machines vont générer le même identifiant; il semble que c'est exactement ce qui s'est passé . En outre, si les classes sont différentes de quelque manière que ce soit (en utilisant différentes versions de la classe), la serialVersionUID
s générée automatiquement sera également différente.
À partir de/de la Serializable
interface docs :
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éfautserialVersionUID
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 valeursserialVersionUID
, car le calcul par défautserialVersionUID
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 uneInvalidClassExceptions
inattendue lors de la désérialisation. Par conséquent, pour garantir une valeurserialVersionUID
cohérente à travers différentes implémentations du compilateur Java, une classe sérialisable doit déclarer une valeurserialVersionUID
explicite. Il est également fortement recommandé que les déclarationsserialVersionUID
explicites utilisent le modificateurprivate
dans la mesure du possible, car elles ne s’appliquent qu'aux champs class_serialVersionUID
déclarant immédiatement ne sont pas utiles en tant que membres hérités. Les classes de tableau ne peuvent pas déclarer une variableserialVersionUID
explicite; elles ont donc toujours la valeur calculée par défaut, mais l'exigence relative à la correspondance des valeursserialVersionUID
est supprimée pour les classes de tableau.
Vous devez définir serialVersionUID
dans la définition de classe, par exemple:
class MyClass implements Serializable {
private static final long serialVersionUID = 6529685098267757690L;
...
Une chose qui aurait pu arriver:
Par conséquent, lors de la compilation de la version X, la machine virtuelle Java générera un premier ID de série (pour la version X) et fera de même avec l'autre version Y (un autre ID de série).
Lorsque votre programme tente de désérialiser les données, il ne le peut pas car les deux classes n'ont pas le même ID de série et votre programme n'a aucune garantie que les deux objets sérialisés correspondent au même format de classe.
En supposant que vous ayez changé de constructeur entre-temps, cela devrait avoir un sens pour vous.
Le message d'exception indique clairement que les versions de classe, qui incluraient également les métadonnées de classe, ont changé au fil du temps. En d'autres termes, la structure de classe lors de la sérialisation n'est pas la même lors de la dé-sérialisation. C'est ce qui est très probablement "en train de se passer".
Je crois que cela se produit car vous utilisez les différentes versions de la même classe sur le client et sur le serveur . Il peut s'agir de champs de données ou de méthodes différentes
La sérialisation en Java n'est pas conçue comme une persistance à long terme ou un format de transport - elle est trop fragile pour cela. À la moindre différence dans le bytecode de classe et la JVM, vos données ne sont plus lisibles. Utilisez la liaison de données XML ou JSON pour votre tâche ( XStream est rapide et facile à utiliser, et il existe de nombreuses alternatives)