Based on the description of SerialVersionUID here: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100, it seems necessary to always include SerialVersionUID in any classes you create so that a JVM used for serialization and a different JVM used for deserialzation won't automatically assign their own SerialVersionUIDs, which have potential to be different from one another because of differences in the JVM. This works well for controlling deserialzation of my own classes, but what if I want to ensure that classes in the standard library serialized with JVM A can be deserialized by JVM B?
Map<Integer, String> myMap = new HashMap<>();
HashMap defines a SerialVersionUID. But:
If it's not guaranteed for standard library classes, does using SerialVersionUID only really ensure proper deserialization for your own classes that never touch the java standard library? For example, a class that looks like this:
public class NewClass implements Serializable
{
private static final long serialVersionUID = 1L;
private final Map<Integer, String> myMap;
public NewClass()
{
this.myMap = new HashMap<>();
}
}
would be prone to failure because deserialization depends on HashMap having the same SerialVersionUID, which could be different in different JVMs, right?
Potentially yes, you are correct.
Actually this has happened to us a while ago with some swing
classes (I really can't remember which exactly), but serializing on jdkX
and de-serailizng them on jdkX+1
(that was a really long time ago, sorry for missing these details), things started to break with InvalidClassException
. We had paid support at the time and opened an issue - the response was, well, that those class(es) changed in such a way that it would be impossible to deserialize them back properly - you are stuck with this version, or upgrade to jdk+1
and use that. It has not happened to me since then, not even once.
Generally, I think, this is what makes serialization hard too. You have to maintain such a process, so that changes in the future versions can be made relevant and compatible with previous ones, from a serialization point of view.
On the other note, HashMap
has a very smart way to serialize it's data. It serializes (among other things likes load_factor
, etc) only it's keys and values - nothing else. So no matter if the implementation changes, they will be possible to be de-serialzied. For this reason, some of the fields that would not be needed are marked as transient, for example:
transient int modCount;
transient Set<Map.Entry<K,V>> entrySet;
The idea is that it should serialize data vs structure.
If HashMap
changes in such a way that Serialization would break in jdk-11
for example, this would make a lot of developers angry, I doubt this would ever be a path taken (unless really needed)