I've been whinging elsewhere about the lack of genuine advanced issues in this Advanced forum, but I think I might have one here. It's about serialisation, so one might argue I/O and Streams is a better forum. Anyway...
I have an application that is required to be able to read saved serialised states from old versions of the application. We fix the serialVersionUID of our own classes, to help to ensure this. However, I have made a mistake.
In one of our classes, I included an array of ProgressType objects, which are objects of a generated CORBA enum type. Being generated code, I can't fix its serialVersionUID. This enum has recently gained some new members, so its serialVersionUID has changed.
Now, when I try to use the latest classes to read one of the objects whose state includes ProgressType, within a serialised state from older versions of the classes, I get an InvalidClassException: -
com.harlequin.DPP.SOAR.RIPInterface.ProgressType; local class incompatible: stream classdesc serialVersionUID = -8705812033005380768, local class serialVersionUID = 1804412345902867916
I am familiar with some of the ways that default serialisation mechanism can be overridden, but cannot immediately see how any of them would help in this situation.
Can anyone think of a way to read one of the old states?
P.S. What I should have done is to store the integer equivalents of the ProgressType enum objects. Primitives don't have serialVersionUIDs. But it's too late now, as states containing ProgressType objects are already out there.
Betty Rubble? Well, I would go with Betty... but I'd be thinking of Wilma.
Well, it's pretty ugly, but one possibility is to use multiple classloaders, each one loaded with a different version of the code. If you get an InvalidClassException, try again with a different classloader.
[Peter]: But it's too late now, as states containing ProgressType objects are already out there.
Are there at least two different versions out there now that you need to support? Or is it just an old version that's been released, and you're trying to make a new version that's compatible with it?
"I'm not back." - Bill Harding, Twister
Joined: Oct 30, 2001
In theory, there could be really old states out there that have yet another different serialVersionUID for ProgressType. In practice, it's very unlikely we will encounter anything except the current released version and the new version under development.
I already concluded it was virtually impossible to read the old states when the serialVersionUID was different in the new class. Luckily, we have our own IDL compiler and we should be able to add a feature to it to allow serialVersionUID to be fixed in a particular generated class. That seems a tidier solution.
I am trying but I don't fully understand your problem. You have a class that contains other classes. And this other class has changed. So the main class is no longer loadable because its trying to load... I'm lost.
Classes are compatible or they are not. You can not have several of the same classes in the same classloader. So only ever 1 serialversionUID will work at a time. You can't use serialversionUID to support multiple file formats.
If you want to have 1 class file able to be compatible with multiple versions of that class file, then you need to fix the serialversionUID and instead store your own identifier. Then you can read that id from the stream first, and that will tell you how to continue on with your deserialization.
At this point I don't think there is anything you can do. the serialversionUID test is done too soon to intercept AFAIK.
One technique I have used in the past is to make all fields transient. Then call stream#defaultWriteObject, then also write other fields manually after the default write. This ensures that if I refactor some benign things like variable names or ordering in the class, it won't affect my saving and loading scheme.