Bonjour
Suite à une refactorisation (ré-usinage, pour les puristes) entrainant une modification de la structure des mes paquetages, une de mes classes sérialisée se retrouve à un autre emplacement.
Pour illustrer, oldPkg.myClass est ma classe avant le refactoring et newPkg.myClass après le refactoring.
Le contenu (méthodes, attributs et serialVersionUID) sont strictement identiques.
Pendant la désérialisation, pas de miracle, je récupère une ClassNotFoundException, ce qui est bien normal.
Pour éviter çà, je voulais redéfinir à la volée le chemin de mon ancienne classe, par la nouvelle.
Pour se faire, j'ai créé une classe surchargeant ObjectInputStream, qui entre en jeu pour la désérialisation.
Cette méthode n'est pas originale, je me suis "inspiré" de ce billet : http://www.norwinter.com/2009/08/20/.../#comment-9635
Voici donc ma nouvelle classe
Voici à l'utilisation, dans la classe initiant la désérialisation :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public class ConvertedObjectInputStream extends ObjectInputStream { public ConvertedObjectInputStream(InputStream in) throws IOException { super(in); } @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { ObjectStreamClass descriptor = super.readClassDescriptor(); // Si oldPkg, alors conversion ! if (descriptor.getName().equals("oldPkg.myClass")) { ObjectStreamClass myOSC = ObjectStreamClass.lookup(newPkg.myClass.class); return myOSC; } return descriptor; } }
Je construis mon ConvertedObjectInputStream grâce à FileInputStream. Quand je fais un readObject de ma classe, la conversion se passe bien.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 FileInputStream fis = new FileInputStream(locator.getFile()); ConvertedObjectInputStream ois = new ConvertedObjectInputStream(fis); try { Object myObject = ois.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); /* ... */ }
Par contre, myClass possède une surcharge de readObject.
Elle essaie de recréer les classes, mais sans la conversion, car elle ne connait pas ConvertedObjectInputStream...
Cette méthode ne reçoit qu'un paramètre : "java.io.ObjectInputStream in"
myClass
Si je laisse tel quel, je me retrouve avec le message d'erreur suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); int nbClasses = in.readInt(); clean(); for (int i = 0; i < nbClasses; i++) { myClass a = (myClass) in.readObject(); add(a); } _classRelations = (Hashtable) in.readObject(); }
Il est donc impossible de réinstancier ma classe ConvertedObjectInputStream car je n'ai qu'un ObjectInputStream, pas un InputStream
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 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 newPkg.myClass.readObject(myClass.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 pour récupérer l'InputStream à partir de ObjectInputStream, afin qu'il soit possible de réinstancier ConvertedObjectInputStream ?
Un autre biais est-il envisageable ?
Michael
Partager