web-dev-qa-db-fra.com

java.io.InvalidClassException: classe locale incompatible:

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?

MODIFIER

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;
}
21
lonesome

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 serialVersionUIDs 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é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 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 variable serialVersionUID explicite; elles ont donc toujours la valeur calculée par défaut, mais l'exigence relative à la correspondance des valeurs serialVersionUID 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;
    ...
35
trutheality

Une chose qui aurait pu arriver:

  • 1: vous créez vos données sérialisées avec une bibliothèque donnée A (version X)
  • 2: vous essayez ensuite de lire ces données avec la même bibliothèque A (mais version Y)

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.

2
belka

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

0
Mark Bramnik

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)

0