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
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;
	}
}
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
 
FileInputStream fis = new FileInputStream(locator.getFile());
ConvertedObjectInputStream ois = new ConvertedObjectInputStream(fis);
try
{
	Object myObject = ois.readObject();
}
catch (ClassNotFoundException e)
{
	e.printStackTrace();
	/* ... */
}
Je construis mon ConvertedObjectInputStream grâce à FileInputStream. Quand je fais un readObject de ma classe, la conversion se passe bien.

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
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();
	}
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
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)
		...
Il est donc impossible de réinstancier ma classe ConvertedObjectInputStream car je n'ai qu'un ObjectInputStream, pas un InputStream


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