2

Imagine I have a class Foo which has had the serialVersionUIDs 1, 3 and 17 in the past and I need to be able to read all three versions into Foo instances. How do I do that?

I specifically need to know which version was saved in the byte stream, so I can do some data migration. How do I get access to the serialVersionUID in readObject()? Or is that already too late?

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820

3 Answers3

2

It is not easy, but possible. For each historical version of class you need to create separate classloader which will load old versions of data-model classes. Then you need to try reading your file with each classloader until some will fit. I believe ObjectInputStream uses current classloader from thread context. Fell free to ask me if you need more details.

Later addition: it seems that it is not so easy to specify which classloader will be used by ObjectInputStream. Additional investigation is probably needed here.

Another later addition: Probably you can override resolveClass(ObjectStreamClass) method in ObjectInputStream to make is use proper class loader.

Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
2

Use different classloaders to deserialize the different versions of the object. After that you have to manually initialize the internal state of the common (probably the latest) instance based on the prevoius versions (you must write a converter for that).

Be sure that your classloader path is totally distinct. If a super classloader can load a class, it will load. So, all classloaders should be totally separate of each other (neither should be the super of the others).

gaborsch
  • 15,408
  • 6
  • 37
  • 48
1

You can get the former serialVersionUID by catching the error during deserialization:

try {
  // deserialize here...
} catch (final java.io.InvalidClassException e) {
  System.out.println(e.getMessage());
  // The message string contains the former uid.
  // Message: local class incompatible: stream classdesc serialVersionUID = OLD_UID_HERE, local class serialVersionUID = NEW_UID_HERE
}
Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
  • OK, but how will he get the data then? – gaborsch Feb 06 '13 at 14:04
  • Well he could parse the message ? At least the uid is not lost and he can do some migration procedure based on this. – Christophe Roussy Feb 06 '13 at 14:05
  • Sure he will not. But he can check out the old source and do a migration (you answer point 1 of his question), I only answer the part about how to find the old uids. – Christophe Roussy Feb 06 '13 at 14:07
  • Thanks :) your solution might work if there are *no changes to the data structure at all* and the serialization would go through to some phase that the object is ready, but "only" the uid is different. But I think the deserialization stops immediately if the iud is different. – gaborsch Feb 06 '13 at 14:10
  • It will stop but with the mentioned exception. But this is the first step to obtain the old uid and take a decision (use according classloader..., not sure about that part) – Christophe Roussy Feb 06 '13 at 14:13
  • Yes, you can make decisions by that message, even go and try a specific classloader (you don't have to try all of them). +1 for that – gaborsch Feb 06 '13 at 14:16