OVH Cloud OVH Cloud

changer serialVersionUID ??

6 réponses
Avatar
pcouas
Bonjour

j'ai actuellement des objets seialise sur differents serveur, avec des
serialVersionUID differents, Cela avant que je ne fige l'UID, existe t
il un moyen de recuperer mes objets ??

Cordialement
Philippe

6 réponses

Avatar
pcouas
Je peux modifier les sources de ma classe reference
j'ai tenté la chose suivante actuellement, mais qui ne donne pas
totale satisfaction

classe de ref objet avec le nouveau UID
classe ancienne obje2 avec l'ancien UID
dans l' inputStream remplacement de la chaine objet par obje2
readObjet avec cast (obje2)input.readObject() (BOOUM ICI )
puis apres copie entre les deux objets par invoke des Methodes get et
set

Dans le read objet cela se passe mal, malgre le remplacement de objet
par obje2 qui a bien l'ancien UID, il detecte il me sort un
InvalidClassCastException

Philippe
Avatar
Hervé AGNOUX
pcouas wrote:

Bonjour

j'ai actuellement des objets seialise sur differents serveur, avec des
serialVersionUID differents, Cela avant que je ne fige l'UID, existe t
il un moyen de recuperer mes objets ??

Cordialement
Philippe


La réponse est OUI, mais malheureusement c'est assez difficile...

Par dessus le marché il faut que tu puisses modifier le code source de la
classe, au moins de celle qui est sur ton serveur "référence". (et si tu
peux modifier les sources partout, alors là c'est beaucoup plus simple : il
suffit de mettre le même serialVersionUID partout, java se débrouille pour
récupérer les différences).

Si tu ne peux modifier que les sources de la version "référence", cela se
passe dans la méthode readObject (et, de là, les ObjectInputStream etc). En
agissant sur la lecture par défaut du flux sérializé, tu peux adapter les
anciennes versions à la nouvelle.

J'ai conscience que ma réponse est un peu légère :-) mais je n'ai plus les
liens et il faut que je recherche les choses... C'est tellement compliqué
que jusqu'à présent je me suis presque toujours débrouillé autrement dans
ce genre de cas.

Si tu n'as pas mieux et si ces premières pistes te permettent pas d'aller
plus loin, j'essaierai de les retrouver :-)



--
Hervé AGNOUX
http://www.diaam-informatique.com

Avatar
Hervé AGNOUX
pcouas wrote:

Je peux modifier les sources de ma classe reference


C'est déjà bien !

j'ai tenté la chose suivante actuellement, mais qui ne donne pas
totale satisfaction

classe de ref objet avec le nouveau UID
classe ancienne obje2 avec l'ancien UID


J'avais cru comprendre que tu avais plus "obj2", donc plusieurs "ancien
UID". Si tu n'en as qu'un tu peux faire que le nouveau UID soit le même que
l'ancien UID. Ce n'est pas intellectuellement satisfaisant, mais,
pratiquement, c'est tellement plus facile...


dans l' inputStream remplacement de la chaine objet par obje2
readObjet avec cast (obje2)input.readObject() (BOOUM ICI )
puis apres copie entre les deux objets par invoke des Methodes get et
set

Dans le read objet cela se passe mal, malgre le remplacement de objet
par obje2 qui a bien l'ancien UID, il detecte il me sort un
InvalidClassCastException



Si jamais tu as plusieurs "ancien UID", je ne connais pas d'autres moyens
que la débrouille.

Il faut commencer par "tromper" le système de désérialization, en
re-écrivant son propre ObjectInputStream, de façon à lui faire croire que
les UID n'ont pas changé. Puis, réparer les dégats qui ne manqueront pas
d'apparaître, par exemple avec l'habituel readObject.

Voici un modèle de ObjectInputStream trompeur :

public class InputStreamCoool extends java.io.ObjectInputStream
{
public InputStreamCoool(InputStream in) throws IOException
{
super(in);
}

// renvoie toujours un "bon" descripteur.
// (c'est à dire, en fait, un mauvais).
@Override
protected ObjectStreamClass readClassDescriptor() throws
IOException, ClassNotFoundException
{
ObjectStreamClass descriptor;
ObjectStreamClass localdescriptor;
Class clazzlocale;

descriptor = super.readClassDescriptor();
clazzlocale = Class.forName(descriptor.getName());
localdescriptor = ObjectStreamClass.lookup(clazzlocale);
if (
descriptor.getSerialVersionUID() ! localdescriptor.getSerialVersionUID())
{
descriptor = localdescriptor; // hum !
}
return descriptor;
}
}

... et tu l'utilises comme un ObjectInputStream dans le style iistream = new
InputStreamCoool(new FileInputStream("fichierUidHumHum.ser"));

L'écriture de la méthode readObject en ces cas est dépendante des
adaptations à réaliser. On est vraiment dans le domaine "Il y a eu une
grosse bourde de faite et on recommencera plus, mais pour l'instant il faut
s'en sortir".

Et, d'ailleurs, comme je réalise des développements au forfait (ou autre),
vous pouvez penser à moi si vous voulez sous-traiter une part de vos
travaux :-) (sinon, continue sur cette liste, si j'ai le temps, j'essaierai
de vous aider).

A ma connaissance, on est obligé de jongler, parce que on ne peut pas créer
de ObjectStreamClass ; le constructeur n'est pas accessible ; donc on ne
peut pas atteindre la finesse - et l'éléguance - de traitement du système
de sérialization/désérialization du JDK.

A+.


--
Hervé AGNOUX
http://www.diaam-informatique.com

Avatar
pcouas
ok, cela resoud une partie de mes soucis
j'ai en plus changer un champ de type, un java.net.url est devenu est
String,
je pense qu'il est possible de detecter ce champ et de faire le cast
avant.
faut juste que je trouve comment

MERCI
Philippe
Avatar
Hervé AGNOUX
pcouas wrote:

ok, cela resoud une partie de mes soucis
j'ai en plus changer un champ de type, un java.net.url est devenu est
String,
je pense qu'il est possible de detecter ce champ et de faire le cast
avant.
faut juste que je trouve comment



Lorsque j'ai à faire ce genre de choses, je me livre à l'infâme bidouille
suivante.

Si la version ancienne est :

private URL lien;


Alors, pour introduire un lien String, je fais :

/** @deprecated */
private URL lien;

private String lienNeuf;


private void readObject () throws...
{
in.defaultReadObject();
if ((lien != null) && (lienNeuf == null))
{
lienNeuf = lien.toString();
lien = null;
}
}

De cette façon, lorsque l'objet sera resérialisé, il sera comme neuf. Et, un
jour, je supprime complètement le champ deprecated.

Le code de "mise à jour" est très variable ; la combine fondamentale est que
vous conservez l'ancienne variable, de façon à la transférer aisément vers
sa nouvelle forme.

Et puis aussi, j'essaie de trouver un nom plus intelligent que "lienNeuf"...

Cordialement.


--
Hervé AGNOUX
http://www.diaam-informatique.com

Avatar
pcouas
Bonjourn


je suis daccord avec vous, sauf que lorsque j'ai fait le changement, je
n'ai pas changer le nom, mais uniquement le "type", et que les objets
serialisés devaient etre des protos, et finalement ils restent.

Est il possible de tester le changement de type de la methode, et de la
modifier avant le basculement de flux ?

Cordialement
Philippe