Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Serialization JAVA6 -> JAVA7

10 réponses
Avatar
news.free.fr
Bonjour,
J'utilise une classe étendant JPanel que je sérialise.

Lors de la dé-sérialisation de JAVA6 -> JAVA7 et inversement, une erreur
InvalidClassException est levée à cause d'une différence de
serialVersionUID dans JComponent.

J'ai éplucher le code, aucune référence à un JComponent n'est faite.
J'utilise uniquement des implémentations de JComponent déclarant
leur propre serialVersionUID.

J'utilise la "Bidouille" suivante pour palier à ce comportement :
==================================================================
public class TGMObjectInputStream
extends ObjectInputStream
{
public TGMObjectInputStream (InputStream is)
throws IOException
{
super (is);
}

/**
* FIXME Grosse magouille.
* {@inheritDoc}
*/
@Override
protected ObjectStreamClass readClassDescriptor ()
throws IOException, ClassNotFoundException
{
ObjectStreamClass descriptor = super.readClassDescriptor ();
Class<?> classLocale = Class.forName (descriptor.getName ());
ObjectStreamClass localDescriptor = ObjectStreamClass.lookup
(classLocale);

if (descriptor.getSerialVersionUID () !=
localDescriptor.getSerialVersionUID ())
descriptor = localDescriptor; // La grosse magouille est là.

return (descriptor);
}
}
======================================================================

Avec ce code je fais à nouveau fonctionner les objets java6 sous java7
et inversement.
Cette manœuvre contourne clairement un mécanisme de sécurité de java.

Deux questions :
- Voyez-vous une solution plus élégante ?
- Existe-t-il un outils permettant de trouver à quelle niveau de
l'objet que je sérialise se trouve le JComponent provoquant
l'InvalidClassException.

10 réponses

Avatar
Christian Laborde
Le 12. 08. 11 09:42, news.free.fr a écrit :
Bonjour,
J'utilise une classe étendant JPanel que je sérialise.

Lors de la dé-sérialisation de JAVA6 -> JAVA7 et
inversement, une erreur InvalidClassException est levée à
cause d'une différence de serialVersionUID dans JComponent.

J'ai éplucher le code, aucune référence à un JComponent
n'est faite. J'utilise uniquement des impl&eacute;mentations
de JComponent déclarant leur propre serialVersionUID.

J'utilise la "Bidouille" suivante pour palier à ce
comportement :
================================================================= >
public class TGMObjectInputStream
extends ObjectInputStream
{
public TGMObjectInputStream (InputStream is)
throws IOException
{
super (is);
}

/**
* FIXME Grosse magouille.
* {@inheritDoc}
*/
@Override
protected ObjectStreamClass readClassDescriptor ()
throws IOException, ClassNotFoundException
{
ObjectStreamClass descriptor = super.readClassDescriptor
();
Class<?> classLocale = Class.forName (descriptor.getName
());
ObjectStreamClass localDescriptor > ObjectStreamClass.lookup (classLocale);

if (descriptor.getSerialVersionUID () ! > localDescriptor.getSerialVersionUID ())
descriptor = localDescriptor; // La grosse magouille
est là.

return (descriptor);
}
}
===================================================================== >

Avec ce code je fais à nouveau fonctionner les objets java6
sous java7 et inversement.
Cette manœuvre contourne clairement un mécanisme de sécurité
de java.

Deux questions :
- Voyez-vous une solution plus élégante ?
- Existe-t-il un outils permettant de trouver à quelle
niveau de l'objet que je sérialise se trouve le JComponent
provoquant l'InvalidClassException.


Il me semble que la réponse est dans l'API :
Class JPanel

java.lang.Object
extended by java.awt.Component
extended by java.awt.Container
extended by javax.swing.JComponent
extended by javax.swing.JPanel

Warning: Serialized objects of this class will not be
compatible with future Swing releases. The current
serialization support is appropriate for short term storage
or RMI between applications running the same version
--
Christian Laborde
La Révolution citoyenne, c'est sur : http://c.lab.over-blog.com/
Les citoyens qui voient Net : http://www.netoyens.info
True E-mail : remove -no-spam-
Sentier des Vinches
CH 1091 Grandvaux
Suisse
Avatar
Francis JUGE-BOIRARD
Tout d'abord merci de votre réponse.

Je connaissais cette "faiblesse" de la sérialisation binaire c'est
pourquoi j'utilise exclusivement des implémentations développées en
interne des JComponent.

En d'autres termes, il n'y a aucun raison évidente pour que le
serialVersionUID de JComponent soit utilisé directement lors de la
sérialisation/dé-sérialisation.

De plus, l'astuce que je cite dans le message d'origine fonctionne
correctement. Il ne s'agit donc pas d'un problème d'encodage binaire
mais bien de l'utilisation du serialVersionUID de JComponent alors même
que je ne l'utilise jamais.

Francis JUGE-BOIRARD
Avatar
mtranchant
Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
Tout d'abord merci de votre réponse.

Je connaissais cette "faiblesse" de la sérialisation binaire
c'est
pourquoi j'utilise exclusivement des implémentations
développées en
interne des JComponent.

En d'autres termes, il n'y a aucun raison évidente pour que le
serialVersionUID de JComponent soit utilisé directement lors de la
sérialisation/dé-sérialisation.

De plus, l'astuce que je cite dans le message d'origine fonctionne
correctement. Il ne s'agit donc pas d'un problème d'encodage binaire
mais bien de l'utilisation du serialVersionUID de JComponent alors même
que je ne l'utilise jamais.

Francis JUGE-BOIRARD


Bonjour,

Je suis désolé de déterrer un topic un peu ancien, mais un peu plus de précision dans votre solution me serait d'un grand secours.
Mon problème se situe sur un problème analogue : dans le cadre d'un refactoring par modification de la structure des paquetages, les classes de mes fichiers sérialisés pointent désormais vers une classe qui n'existe plus. Je voulais utiliser le mécanisme pour modifier à la volée le chemin, ce qui devrait être techniquement possible par ce biais :

public class ConvertedObjectInputStream extends ObjectInputStream
{
public ConvertedObjectInputStream(ObjectInputStream in) throws IOException
{
super(in);
}

public ConvertedObjectInputStream(FileInputStream in) throws IOException
{
super(in);
}

@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
{

ObjectStreamClass descriptor = super.readClassDescriptor();

if (descriptor.getName().equals("oldPkg.myClass"))
{
ObjectStreamClass myOSC = ObjectStreamClass.lookup(newPkg.myClass.class);
return myOSC;
}

return descriptor;
}
}

Cependant, c'est à l'utilisation de cette classe que j'ai un problème. Je construis mon ConvertedObjectInputStream grâce à FileInputStream (si je passe par ObjectInputStream, j'ai un EOFException...) mais lorsque je fais un readObject de ma classe, elle ne passe pas par ma méthode surchargée, comme l'indique ma pile d'erreur :

java.lang.ClassNotFoundException: oldPkg.myClass
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:603)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
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)
at org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at newPkg.readingClass.readDataFromSerialFile(readingClass.java:203)

Une idée sur ce que j'ai pu faire de travers ?
Merci d'avance
Avatar
mtranchant
mtranchant a écrit le 26/01/2012 à 11h09 :
Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
Tout d'abord merci de votre réponse.

Je connaissais cette "faiblesse" de la sérialisation binaire
c'est
pourquoi j'utilise exclusivement des implémentations
développées en
interne des JComponent.

En d'autres termes, il n'y a aucun raison évidente pour que le
serialVersionUID de JComponent soit utilisé directement lors de la
sérialisation/dé-sérialisation.

De plus, l'astuce que je cite dans le message d'origine fonctionne
correctement. Il ne s'agit donc pas d'un problème d'encodage binaire
mais bien de l'utilisation du serialVersionUID de JComponent alors même
que je ne l'utilise jamais.

Francis JUGE-BOIRARD



Bonjour,

Je suis désolé de déterrer un topic un peu ancien, mais un
peu plus de précision dans votre solution me serait d'un grand secours.
Mon problème se situe sur un problème analogue : dans le cadre
d'un refactoring par modification de la structure des paquetages, les classes
de mes fichiers sérialisés pointent désormais vers une
classe qui n'existe plus. Je voulais utiliser le mécanisme pour modifier
à la volée le chemin, ce qui devrait être techniquement
possible par ce biais :

public class ConvertedObjectInputStream extends ObjectInputStream
{
public ConvertedObjectInputStream(ObjectInputStream in) throws IOException
{
super(in);
}

public ConvertedObjectInputStream(FileInputStream in) throws IOException
{
super(in);
}

@Override
protected ObjectStreamClass readClassDescriptor() throws IOException,
ClassNotFoundException
{

ObjectStreamClass descriptor = super.readClassDescriptor();

if (descriptor.getName().equals("oldPkg.myClass"))
{
ObjectStreamClass myOSC = ObjectStreamClass.lookup(newPkg.myClass.class);
return myOSC;
}

return descriptor;
}
}

Cependant, c'est à l'utilisation de cette classe que j'ai un
problème. Je construis mon ConvertedObjectInputStream grâce
à FileInputStream (si je passe par ObjectInputStream, j'ai un
EOFException...) mais lorsque je fais un readObject de ma classe, elle ne passe
pas par ma méthode surchargée, comme l'indique ma pile d'erreur :

java.lang.ClassNotFoundException: oldPkg.myClass
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:603)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
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)
at org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at newPkg.readingClass.readDataFromSerialFile(readingClass.java:203)

Une idée sur ce que j'ai pu faire de travers ?
Merci d'avance


Erreur de ma part sur le constructeur, il s'agit de ConvertedObjectInputStream(InputStream in) pas de ConvertedObjectInputStream(ObjectInputStream in)

Le problème reste entier, mais au niveau du readObject de myClass, car il m'est impossible d'instancier ma classe ConvertedObjectInputStream avec un ObjectInputStream ...
Avatar
Yliur
Le Thu, 26 Jan 2012 04:09:31 -0600
mtranchant a écrit :

Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
> Tout d'abord merci de votre réponse.
>
> Je connaissais cette "faiblesse" de la sérialisation binaire
> c'est
> pourquoi j'utilise exclusivement des implémentations
> développées en
> interne des JComponent.
>
> En d'autres termes, il n'y a aucun raison évidente pour que le
> serialVersionUID de JComponent soit utilisé directement lors de la
> sérialisation/dé-sérialisation.
>
> De plus, l'astuce que je cite dans le message d'origine fonctionne
> correctement. Il ne s'agit donc pas d'un problème d'encodage binaire
> mais bien de l'utilisation du serialVersionUID de JComponent alors
> même que je ne l'utilise jamais.
>
> Francis JUGE-BOIRARD
Bonjour,

Je suis désolé de déterrer un topic un peu ancien, mais un peu plus de
précision dans votre solution me serait d'un grand secours.
Mon problème se situe sur un problème analogue : dans le cadre d'un
refactoring par modification de la structure des paquetages, les
classes de mes fichiers sérialisés pointent désormais vers une classe
qui n'existe plus. Je voulais utiliser le mécanisme pour modifier à
la volée le chemin, ce qui devrait être techniquement possible par ce
biais :



C'est sûr ça ? Ça doit dépendre de la liste des endroits où c'est
écrit... Est-ce que le graphe d'objets est complexe ou est-ce qu'il
s'agit d'une simple liste d'objets ?

As-tu regardé si la méthode que tu redéfinis est exécutée ou non à un
moment donné, avec une trace par exemple ?

Il y en a beaucoup des fichiers contenant les données ? Ce sera
peut-être plus facile de les charger avec les anciennes classes, faire
la copie en mémoire dans les nouvelles classes et les resauvegarder
avec ?

Pour les détails de la sérialisation, je ne sais pas trop
malheureusement...

Jeter un oeil sur le code source de la classe ObjectInputStream
fournira peut-être plus de renseignements sur son fonctionnement (la
méthode readObject notamment) ? Peut-être que redéfinir cette méthode
pour y insérer quelques traces pourra fournir des informations plus
précises ?
Avatar
mtranchant
Yliur a écrit le 26/01/2012 à 14h36 :
Le Thu, 26 Jan 2012 04:09:31 -0600
mtranchant a écrit :

Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
> Tout d'abord merci de votre réponse.
>
> Je connaissais cette "faiblesse" de la sérialisation
binaire
> c'est
> pourquoi j'utilise exclusivement des implémentations
> développées en
> interne des JComponent.
>
> En d'autres termes, il n'y a aucun raison évidente pour que le
> serialVersionUID de JComponent soit utilisé directement lors de la
> sérialisation/dé-sérialisation.
>
> De plus, l'astuce que je cite dans le message d'origine fonctionne
> correctement. Il ne s'agit donc pas d'un problème d'encodage
binaire
> mais bien de l'utilisation du serialVersionUID de JComponent alors
> même que je ne l'utilise jamais.
>
> Francis JUGE-BOIRARD
Bonjour,

Je suis désolé de déterrer un topic un peu ancien, mais
un peu plus de
précision dans votre solution me serait d'un grand secours.
Mon problème se situe sur un problème analogue : dans le cadre
d'un
refactoring par modification de la structure des paquetages, les
classes de mes fichiers sérialisés pointent désormais
vers une classe
qui n'existe plus. Je voulais utiliser le mécanisme pour modifier
à
la volée le chemin, ce qui devrait être techniquement possible
par ce
biais :




C'est sûr ça ? Ça doit dépendre de la liste des
endroits où c'est
écrit... Est-ce que le graphe d'objets est complexe ou est-ce qu'il
s'agit d'une simple liste d'objets ?

As-tu regardé si la méthode que tu redéfinis est
exécutée ou non à un
moment donné, avec une trace par exemple ?

Il y en a beaucoup des fichiers contenant les données ? Ce sera
peut-être plus facile de les charger avec les anciennes classes, faire
la copie en mémoire dans les nouvelles classes et les resauvegarder
avec ?

Pour les détails de la sérialisation, je ne sais pas trop
malheureusement...

Jeter un oeil sur le code source de la classe ObjectInputStream
fournira peut-être plus de renseignements sur son fonctionnement (la
méthode readObject notamment) ? Peut-être que redéfinir
cette méthode
pour y insérer quelques traces pourra fournir des informations plus
précises ?


Bonjour,

Merci d'avoir pris le temps de lire mon problème.
readObject est en "final", impossible de la surcharger...

En fait, j'ai fait une erreur dans mon analyse initiale.
Lorsque j'initie la désérialisation, mon ConvertedObjectInputStream intervient bien, ce qui me rassure quelque peu. Je me retrouve bien dans la newPkg.myClass .
Par contre, cette classe, que je désérialise, possède elle aussi une méthode readObject sur la trame :
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException

C'est là où le problème se situe :
J'obtiens donc un ObjectInputStream au lieu de mon ConvertedObjectInputStream, et même si ConvertedObjectInputStream hérite de ObjectInputStream, je ne peux construire une instance de ConvertedObjectInputStream grâce à un ObjectInputStream, il me faudrait le (File)InputStream qui l'a créé.

Mais à ma connaissance, çà n'est pas possible, sauf si vous avez une idée à ce sujet ?

Merci encore
Michael
Avatar
Yliur
Le Thu, 26 Jan 2012 09:28:32 -0600
mtranchant a écrit :

Yliur a écrit le 26/01/2012 à 14h36 :
> Le Thu, 26 Jan 2012 04:09:31 -0600
> mtranchant a écrit :
>
>> Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
>> > Tout d'abord merci de votre réponse.
>> >
>> > Je connaissais cette "faiblesse" de la sérialisation
>> binaire
>> > c'est
>> > pourquoi j'utilise exclusivement des implémentations
>> > développées en
>> > interne des JComponent.
>> >
>> > En d'autres termes, il n'y a aucun raison évidente pour que le
>> > serialVersionUID de JComponent soit utilisé directement lors de
>> > la sérialisation/dé-sérialisation.
>> >
>> > De plus, l'astuce que je cite dans le message d'origine
>> > fonctionne correctement. Il ne s'agit donc pas d'un problème
>> > d'encodage
>> binaire
>> > mais bien de l'utilisation du serialVersionUID de JComponent
>> > alors même que je ne l'utilise jamais.
>> >
>> > Francis JUGE-BOIRARD
>> Bonjour,
>>
>> Je suis désolé de déterrer un topic un peu ancien, mais
>> un peu plus de
>> précision dans votre solution me serait d'un grand secours.
>> Mon problème se situe sur un problème analogue : dans le cadre
>> d'un
>> refactoring par modification de la structure des paquetages, les
>> classes de mes fichiers sérialisés pointent désormais
>> vers une classe
>> qui n'existe plus. Je voulais utiliser le mécanisme pour modifier
>> à
>> la volée le chemin, ce qui devrait être techniquement possible
>> par ce
>> biais :
>>
>>
> C'est sûr ça ? Ça doit dépendre de la liste des
> endroits où c'est
> écrit... Est-ce que le graphe d'objets est complexe ou est-ce qu'il
> s'agit d'une simple liste d'objets ?
>
> As-tu regardé si la méthode que tu redéfinis est
> exécutée ou non à un
> moment donné, avec une trace par exemple ?
>
> Il y en a beaucoup des fichiers contenant les données ? Ce sera
> peut-être plus facile de les charger avec les anciennes classes,
> faire la copie en mémoire dans les nouvelles classes et les
> resauvegarder avec ?
>
> Pour les détails de la sérialisation, je ne sais pas trop
> malheureusement...
>
> Jeter un oeil sur le code source de la classe ObjectInputStream
> fournira peut-être plus de renseignements sur son fonctionnement (la
> méthode readObject notamment) ? Peut-être que redéfinir
> cette méthode
> pour y insérer quelques traces pourra fournir des informations plus
> précises ?
Bonjour,

Merci d'avoir pris le temps de lire mon problème.
readObject est en "final", impossible de la surcharger...

En fait, j'ai fait une erreur dans mon analyse initiale.
Lorsque j'initie la désérialisation, mon ConvertedObjectInputStream
intervient bien, ce qui me rassure quelque peu. Je me retrouve bien
dans la newPkg.myClass




Dans la pile d'appels, il y a ça :
at org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Est-ce une des nouvelles classes ? Est-ce que sa méthode readObject est
implémentée ?

Étrange, on dirait qu'à partir de là un objet est lu et qu'une méthode
readClassDesc (plutôt que readClassDescriptor) est appelée. Est-ce que
cette méthode ne peut pas être redéfinie ? Est-ce une méthode privée de
ObjectInputStream ?

Est-ce que sur un exemple beaucoup plus simple (un seul objet) un
rechargement avec les nouvelles classes fonctionne ?

Peut-être que redéfinir resolveClass pourrait être intéressant, mais je
ne sais pas si fournir une "mauvaise" classe va fonctionner. A essayer
quand même, la vérification semble se faire avec serialVersionUID, qui
doit être le même pour l'ancienne et la nouvelle classe.
Avatar
mtranchant
Yliur a écrit le 26/01/2012 à 17h49 :
Le Thu, 26 Jan 2012 09:28:32 -0600
mtranchant a écrit :

Yliur a écrit le 26/01/2012 à 14h36 :
> Le Thu, 26 Jan 2012 04:09:31 -0600
> mtranchant a écrit :
>
>> Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
>> > Tout d'abord merci de votre réponse.
>> >
>> > Je connaissais cette "faiblesse" de la
sérialisation
>> binaire
>> > c'est
>> > pourquoi j'utilise exclusivement des implémentations
>> > développées en
>> > interne des JComponent.
>> >
>> > En d'autres termes, il n'y a aucun raison évidente pour
que le
>> > serialVersionUID de JComponent soit utilisé directement
lors de
>> > la sérialisation/dé-sérialisation.
>> >
>> > De plus, l'astuce que je cite dans le message d'origine
>> > fonctionne correctement. Il ne s'agit donc pas d'un
problème
>> > d'encodage
>> binaire
>> > mais bien de l'utilisation du serialVersionUID de JComponent
>> > alors même que je ne l'utilise jamais.
>> >
>> > Francis JUGE-BOIRARD
>> Bonjour,
>>
>> Je suis désolé de déterrer un topic un peu
ancien, mais
>> un peu plus de
>> précision dans votre solution me serait d'un grand secours.
>> Mon problème se situe sur un problème analogue : dans
le cadre
>> d'un
>> refactoring par modification de la structure des paquetages, les
>> classes de mes fichiers sérialisés pointent
désormais
>> vers une classe
>> qui n'existe plus. Je voulais utiliser le mécanisme pour
modifier
>> à
>> la volée le chemin, ce qui devrait être techniquement
possible
>> par ce
>> biais :
>>
>>
> C'est sûr ça ? Ça doit dépendre de la liste
des
> endroits où c'est
> écrit... Est-ce que le graphe d'objets est complexe ou est-ce
qu'il
> s'agit d'une simple liste d'objets ?
>
> As-tu regardé si la méthode que tu redéfinis est
> exécutée ou non à un
> moment donné, avec une trace par exemple ?
>
> Il y en a beaucoup des fichiers contenant les données ? Ce sera
> peut-être plus facile de les charger avec les anciennes classes,
> faire la copie en mémoire dans les nouvelles classes et les
> resauvegarder avec ?
>
> Pour les détails de la sérialisation, je ne sais pas trop
> malheureusement...
>
> Jeter un oeil sur le code source de la classe ObjectInputStream
> fournira peut-être plus de renseignements sur son fonctionnement
(la
> méthode readObject notamment) ? Peut-être que
redéfinir
> cette méthode
> pour y insérer quelques traces pourra fournir des informations
plus
> précises ?
Bonjour,

Merci d'avoir pris le temps de lire mon problème.
readObject est en "final", impossible de la surcharger...

En fait, j'ai fait une erreur dans mon analyse initiale.
Lorsque j'initie la désérialisation, mon
ConvertedObjectInputStream
intervient bien, ce qui me rassure quelque peu. Je me retrouve bien
dans la newPkg.myClass





Dans la pile d'appels, il y a ça :
at org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Est-ce une des nouvelles classes ? Est-ce que sa méthode readObject est
implémentée ?

Étrange, on dirait qu'à partir de là un objet est lu et
qu'une méthode
readClassDesc (plutôt que readClassDescriptor) est appelée. Est-ce
que
cette méthode ne peut pas être redéfinie ? Est-ce une
méthode privée de
ObjectInputStream ?

Est-ce que sur un exemple beaucoup plus simple (un seul objet) un
rechargement avec les nouvelles classes fonctionne ?

Peut-être que redéfinir resolveClass pourrait être
intéressant, mais je
ne sais pas si fournir une "mauvaise" classe va fonctionner. A
essayer
quand même, la vérification semble se faire avec serialVersionUID,
qui
doit être le même pour l'ancienne et la nouvelle classe.


Bonjour,

Effectivement org.steamer.hypercarte.serials.AreaSet est newPkg.myClass (un oubli de simplification)
readObject est implémentée, en effet, d'où mon problème car, c'est à cet endroit que l'ObjectInputStream "simple" (non surchargé) est utilisé : il n'y a donc pas de conversion vers le nouveau paquetage dans cette méthode.

readClassDescriptor est redéfinie, mais sur ConvertedObjectInpuStream, le problème est qu'à partir d'un ObjectInpuStream, on ne peut instancier ni un autre ObjectInpuStream ni ma version de ConvertedObjectInpuStream : il faut un InputStream .
Donc, même remarque sur resolveClass...
Pourtant les deux versions de myClass sont strictement identiques, c'est navrant...

Pour tests :
J'ai recréé les anciennes classes, maintenant, j'obtiens un ClassCastException entre mes anciennes et mes nouvelles classes. Je vais voir si je ne peux pas bricoler quelquechose en ce sens.... Mais çà sera toujours moins propre que la première solution...

Merci de votre aide
Michael
Avatar
Yliur
Le Fri, 27 Jan 2012 03:13:36 -0600
mtranchant a écrit :

Yliur a écrit le 26/01/2012 à 17h49 :
> Le Thu, 26 Jan 2012 09:28:32 -0600
> mtranchant a écrit :
>
>> Yliur a écrit le 26/01/2012 à 14h36 :
>> > Le Thu, 26 Jan 2012 04:09:31 -0600
>> > mtranchant a écrit :
>> >
>> >> Francis JUGE-BOIRARD a écrit le 12/08/2011 à 12h05 :
>> >> > Tout d'abord merci de votre réponse.
>> >> >
>> >> > Je connaissais cette "faiblesse" de la
>> sérialisation
>> >> binaire
>> >> > c'est
>> >> > pourquoi j'utilise exclusivement des implémentations
>> >> > développées en
>> >> > interne des JComponent.
>> >> >
>> >> > En d'autres termes, il n'y a aucun raison évidente pour
>> que le
>> >> > serialVersionUID de JComponent soit utilisé directement
>> lors de
>> >> > la sérialisation/dé-sérialisation.
>> >> >
>> >> > De plus, l'astuce que je cite dans le message d'origine
>> >> > fonctionne correctement. Il ne s'agit donc pas d'un
>> problème
>> >> > d'encodage
>> >> binaire
>> >> > mais bien de l'utilisation du serialVersionUID de JComponent
>> >> > alors même que je ne l'utilise jamais.
>> >> >
>> >> > Francis JUGE-BOIRARD
>> >> Bonjour,
>> >>
>> >> Je suis désolé de déterrer un topic un peu
>> ancien, mais
>> >> un peu plus de
>> >> précision dans votre solution me serait d'un grand secours.
>> >> Mon problème se situe sur un problème analogue : dans
>> le cadre
>> >> d'un
>> >> refactoring par modification de la structure des paquetages, les
>> >> classes de mes fichiers sérialisés pointent
>> désormais
>> >> vers une classe
>> >> qui n'existe plus. Je voulais utiliser le mécanisme pour
>> modifier
>> >> à
>> >> la volée le chemin, ce qui devrait être techniquement
>> possible
>> >> par ce
>> >> biais :
>> >>
>> >>
>> > C'est sûr ça ? Ça doit dépendre de la liste
>> des
>> > endroits où c'est
>> > écrit... Est-ce que le graphe d'objets est complexe ou est-ce
>> qu'il
>> > s'agit d'une simple liste d'objets ?
>> >
>> > As-tu regardé si la méthode que tu redéfinis est
>> > exécutée ou non à un
>> > moment donné, avec une trace par exemple ?
>> >
>> > Il y en a beaucoup des fichiers contenant les données ? Ce sera
>> > peut-être plus facile de les charger avec les anciennes classes,
>> > faire la copie en mémoire dans les nouvelles classes et les
>> > resauvegarder avec ?
>> >
>> > Pour les détails de la sérialisation, je ne sais pas trop
>> > malheureusement...
>> >
>> > Jeter un oeil sur le code source de la classe ObjectInputStream
>> > fournira peut-être plus de renseignements sur son fonctionnement
>> (la
>> > méthode readObject notamment) ? Peut-être que
>> redéfinir
>> > cette méthode
>> > pour y insérer quelques traces pourra fournir des informations
>> plus
>> > précises ?
>> Bonjour,
>>
>> Merci d'avoir pris le temps de lire mon problème.
>> readObject est en "final", impossible de la surcharger...
>>
>> En fait, j'ai fait une erreur dans mon analyse initiale.
>> Lorsque j'initie la désérialisation, mon
>> ConvertedObjectInputStream
>> intervient bien, ce qui me rassure quelque peu. Je me retrouve bien
>> dans la newPkg.myClass
>>
>>
>>
> Dans la pile d'appels, il y a ça :
> at
> org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>
> Est-ce une des nouvelles classes ? Est-ce que sa méthode readObject
> est implémentée ?
>
> Étrange, on dirait qu'à partir de là un objet est lu et
> qu'une méthode
> readClassDesc (plutôt que readClassDescriptor) est appelée. Est-ce
> que
> cette méthode ne peut pas être redéfinie ? Est-ce une
> méthode privée de
> ObjectInputStream ?
>
> Est-ce que sur un exemple beaucoup plus simple (un seul objet) un
> rechargement avec les nouvelles classes fonctionne ?
>
> Peut-être que redéfinir resolveClass pourrait être
> intéressant, mais je
> ne sais pas si fournir une "mauvaise" classe va fonctionner. A
> essayer
> quand même, la vérification semble se faire avec serialVersionUID,
> qui
> doit être le même pour l'ancienne et la nouvelle classe.
Bonjour,

Effectivement org.steamer.hypercarte.serials.AreaSet est
newPkg.myClass (un oubli de simplification)
readObject est implémentée, en effet, d'où mon problème car, c'est à
cet endroit que l'ObjectInputStream "simple" (non surchargé) est
utilisé : il n'y a donc pas de conversion vers le nouveau paquetage
dans cette méthode.



Cette méthode a été implémentée mais vous ne pouvez pas la changer ?


readClassDescriptor est redéfinie, mais sur
ConvertedObjectInpuStream, le problème est qu'à partir d'un
ObjectInpuStream, on ne peut instancier ni un autre ObjectInpuStream
ni ma version de ConvertedObjectInpuStream : il faut un InputStream .
Donc, même remarque sur resolveClass...
Pourtant les deux versions de myClass sont strictement identiques,
c'est navrant...

Pour tests :
J'ai recréé les anciennes classes, maintenant, j'obtiens un
ClassCastException entre mes anciennes et mes nouvelles classes. Je
vais voir si je ne peux pas bricoler quelquechose en ce sens.... Mais
çà sera toujours moins propre que la première solution...



Les anciennes classes pourraient peut-être hériter des nouvelles, juste
pour la compatibilité. Le bricolage n'est pas très grave si c'est à
court terme (pour convertir des données), c'est plus ennuyeux s'il faut
le conserver parce que le programme doit pouvoir relire des données qui
arrivent d'ailleurs par exemple. Auquel cas le mécanisme de base de
sérialisation de Java n'est sans doute pas le plus indiqué. A la base
il s'agit moins de persistance que de transférer des objets d'une
machine à une autre.
Avatar
mtranchant
Yliur a écrit le 27/01/2012 à 14h42 :
Le Fri, 27 Jan 2012 03:13:36 -0600
mtranchant a écrit :

Yliur a écrit le 26/01/2012 à 17h49 :
> Le Thu, 26 Jan 2012 09:28:32 -0600
> mtranchant a écrit :
>
>> Yliur a écrit le 26/01/2012 à 14h36 :
>> > Le Thu, 26 Jan 2012 04:09:31 -0600
>> > mtranchant a écrit :
>> >
>> >> Francis JUGE-BOIRARD a écrit le 12/08/2011 à
12h05 :
>> >> > Tout d'abord merci de votre réponse.
>> >> >
>> >> > Je connaissais cette "faiblesse" de la
>> sérialisation
>> >> binaire
>> >> > c'est
>> >> > pourquoi j'utilise exclusivement des
implémentations
>> >> > développées en
>> >> > interne des JComponent.
>> >> >
>> >> > En d'autres termes, il n'y a aucun raison
évidente pour
>> que le
>> >> > serialVersionUID de JComponent soit utilisé
directement
>> lors de
>> >> > la sérialisation/dé-sérialisation.
>> >> >
>> >> > De plus, l'astuce que je cite dans le message d'origine
>> >> > fonctionne correctement. Il ne s'agit donc pas d'un
>> problème
>> >> > d'encodage
>> >> binaire
>> >> > mais bien de l'utilisation du serialVersionUID de
JComponent
>> >> > alors même que je ne l'utilise jamais.
>> >> >
>> >> > Francis JUGE-BOIRARD
>> >> Bonjour,
>> >>
>> >> Je suis désolé de déterrer un topic un
peu
>> ancien, mais
>> >> un peu plus de
>> >> précision dans votre solution me serait d'un grand
secours.
>> >> Mon problème se situe sur un problème analogue
: dans
>> le cadre
>> >> d'un
>> >> refactoring par modification de la structure des paquetages,
les
>> >> classes de mes fichiers sérialisés pointent
>> désormais
>> >> vers une classe
>> >> qui n'existe plus. Je voulais utiliser le mécanisme
pour
>> modifier
>> >> à
>> >> la volée le chemin, ce qui devrait être
techniquement
>> possible
>> >> par ce
>> >> biais :
>> >>
>> >>
>> > C'est sûr ça ? Ça doit dépendre de la
liste
>> des
>> > endroits où c'est
>> > écrit... Est-ce que le graphe d'objets est complexe ou
est-ce
>> qu'il
>> > s'agit d'une simple liste d'objets ?
>> >
>> > As-tu regardé si la méthode que tu
redéfinis est
>> > exécutée ou non à un
>> > moment donné, avec une trace par exemple ?
>> >
>> > Il y en a beaucoup des fichiers contenant les données ?
Ce sera
>> > peut-être plus facile de les charger avec les anciennes
classes,
>> > faire la copie en mémoire dans les nouvelles classes et
les
>> > resauvegarder avec ?
>> >
>> > Pour les détails de la sérialisation, je ne sais
pas trop
>> > malheureusement...
>> >
>> > Jeter un oeil sur le code source de la classe ObjectInputStream
>> > fournira peut-être plus de renseignements sur son
fonctionnement
>> (la
>> > méthode readObject notamment) ? Peut-être que
>> redéfinir
>> > cette méthode
>> > pour y insérer quelques traces pourra fournir des
informations
>> plus
>> > précises ?
>> Bonjour,
>>
>> Merci d'avoir pris le temps de lire mon problème.
>> readObject est en "final", impossible de la surcharger...
>>
>> En fait, j'ai fait une erreur dans mon analyse initiale.
>> Lorsque j'initie la désérialisation, mon
>> ConvertedObjectInputStream
>> intervient bien, ce qui me rassure quelque peu. Je me retrouve bien
>> dans la newPkg.myClass
>>
>>
>>
> Dans la pile d'appels, il y a ça :
> at
> org.steamer.hypercarte.serials.AreaSet.readObject(AreaSet.java:210)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>
> Est-ce une des nouvelles classes ? Est-ce que sa méthode
readObject
> est implémentée ?
>
> Étrange, on dirait qu'à partir de là un objet est lu
et
> qu'une méthode
> readClassDesc (plutôt que readClassDescriptor) est appelée.
Est-ce
> que
> cette méthode ne peut pas être redéfinie ? Est-ce une
> méthode privée de
> ObjectInputStream ?
>
> Est-ce que sur un exemple beaucoup plus simple (un seul objet) un
> rechargement avec les nouvelles classes fonctionne ?
>
> Peut-être que redéfinir resolveClass pourrait être
> intéressant, mais je
> ne sais pas si fournir une "mauvaise" classe va fonctionner. A
> essayer
> quand même, la vérification semble se faire avec
serialVersionUID,
> qui
> doit être le même pour l'ancienne et la nouvelle classe.
Bonjour,

Effectivement org.steamer.hypercarte.serials.AreaSet est
newPkg.myClass (un oubli de simplification)
readObject est implémentée, en effet, d'où mon
problème car, c'est à
cet endroit que l'ObjectInputStream "simple" (non surchargé)
est
utilisé : il n'y a donc pas de conversion vers le nouveau paquetage
dans cette méthode.




Cette méthode a été implémentée mais vous ne
pouvez pas la changer ?


readClassDescriptor est redéfinie, mais sur
ConvertedObjectInpuStream, le problème est qu'à partir d'un
ObjectInpuStream, on ne peut instancier ni un autre ObjectInpuStream
ni ma version de ConvertedObjectInpuStream : il faut un InputStream .
Donc, même remarque sur resolveClass...
Pourtant les deux versions de myClass sont strictement identiques,
c'est navrant...

Pour tests :
J'ai recréé les anciennes classes, maintenant, j'obtiens un
ClassCastException entre mes anciennes et mes nouvelles classes. Je
vais voir si je ne peux pas bricoler quelquechose en ce sens.... Mais
çà sera toujours moins propre que la première solution...




Les anciennes classes pourraient peut-être hériter des nouvelles,
juste
pour la compatibilité. Le bricolage n'est pas très grave si c'est
à
court terme (pour convertir des données), c'est plus ennuyeux s'il faut
le conserver parce que le programme doit pouvoir relire des données qui
arrivent d'ailleurs par exemple. Auquel cas le mécanisme de base de
sérialisation de Java n'est sans doute pas le plus indiqué. A la
base
il s'agit moins de persistance que de transférer des objets d'une
machine à une autre.
Cette méthode a été implémentée mais vous ne pouvez pas la changer ?


Si, bien sûr, mais il s'agit de l'attribut passé à la méthode. Sur lui, je ne peux agir, or, c'est lui qui détient la clé de mon problème.

il s'agit moins de persistance que de transférer des objets d'une machine à une autre.


Je suis entièrement d'accord, mais il s'agit de vieilles décisions, avec lesquelles il faut maintenant composer.

Pour info, j'ai abandonné la manip, et je reviens, pour mes classes sérialisées, à la structure précédente. La méthode de sauvegarde/lecture étant en pourparlers pour une version ultérieure.

Merci de votre aide !
Michael