I have read various blogs about Serialization and the use of serialVersionUID. Most of them mention using it to maintain the state of a serializable class.
The scenario I have is;
I know the old serialVersionUID and the new serialVersionUID.
On reading in an object with the old serialVersionUID I want to manipulate the data so it fits the new version, I only want to bother to do this if the object I am reading in is of the old type.
This seems like something that should be very straight forwards!
Is there a way to get hold of the serialVersionUID as the object is read in?
The InvalidClassException is thrown before the readObject method in the serialized class is invoked so I can’t access it there.
The only hint I have found is to override the ObjectInputStream so that readClassDescriptor() is available although this seems a heavy weight solution to what must be a common problem!
All help is gratefully received!
M
I am going to present a few possible ways to support older versions of a class/interface in serialization:
Use Migrators
In such a case you need the following in your Java project:
@DeprecatedLet me say from the beginning that it’s not always possible to work with objects of older versions (see the Oracle documentation on versioning of serializable objects). For the sake of simplicity, let us assume that while upgrading, your classes always implement the interface
IEntitythat you have defined.And assume that you initially work with the class:
If you need to upgrade the class
Entityinto a new implementation with a new serialVersionUID, then first annotate it as@Deprecatedbut don’t rename it and don’t move it to another package :Now create your new implementation with a new serialVersionUID (important) and an additional constructor as follows…
Of course the most critical part of the whole procedure is how you implement the above constructor. If you have serialized some objects of the old type
Entityas binary files (using for exampleObjectOutputStream) and you have now migrated toEntity_newyou can parse them as instances ofEntityand then convert them into instances ofEntity_new. Here is an example:There are of course other alternative that don’t require that particular constructor or use java reflection. There are lots of other design approaches one can choose. Note also that exception handling and checks for null objects have been completely omitted for the sake of simplicity in the above code.
Design a generic serializable interface
If applicable, you can try in the first place to design an interface for your class that is not likely to change in the future. If your class needs to store a set of properties that is very likely to be modified, consider using a
Map<String, Object>for this purpose, whereStringrefers to the property name/identifier andObjectis the corresponding value.Customize readObject and writeObject
There is yet another way to provide support for older version which I will mention for completeness, but is not one I would choose. You can implement
private void readObject(ObjectInputStream in)andprivate void writeObject(ObjectOutputStream out)in a way that it accommodates both the current and all previous versions of your class/interface. I am not sure whether something like this is always feasible and sustainable and you may end up having a very messy and lengthy implementation of these methods.Alternative serialization techniques
This doesn’t answer the OP’s question, but I reckon it is worth bringing it up. You may consider serializing your object in some ASCII format such as JSON, YAML or XML. In such a case, unless you vehemently redesign your serializable interface, extensibility comes out of the box. BSON (binary JSON) is a good choice if you are looking for an extensible binary protocol. Maybe this is the best way to go to provide portability of your objects across software that may not be implemented in Java.