GNT sans publicité, site mobile, fonctionnalitées exclusives...

Serialization JAVA6 -> JAVA7

Le
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.
Lire les 10 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Christian Laborde
Le #23648451
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 ());
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
Francis JUGE-BOIRARD
Le #23648721
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
mtranchant Hors ligne
Le #24197241
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
mtranchant Hors ligne
Le #24197381
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 ...
Yliur
Le #24197821
Le Thu, 26 Jan 2012 04:09:31 -0600
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 :



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 ?
Publicité
Suivre les réponses
Poster une réponse
Anonyme