Eclipse issues warnings when a serialVersionUID
is missing.
The serializable class Foo does not declare a static final serialVersionUID field of type long
What is serialVersionUID
and why is it important? Please show an example where missing serialVersionUID
will cause a problem.
This question is very well documented in Effective Java by Joshua Bloch. A very good book and a must read. I will outline some of the reasons below :
The serialization runtime comes up with a number called Serial version for each serializable class. This number is called serialVersionUID. Now there is some Math behind this number and it comes out based on the fields/methods that are defined in the class. For the same class the same version is generated every time. This number is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException.
If the class is serializable you can also declare your own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long. Most IDE's like Eclipse help you generate that long string.
serialVersionUID
facilitates versioning of serialized data. Its value is stored with the data when serializing. When de-serializing, the same version is checked to see how the serialized data matches the current code.If you want to version your data, you normally start with a
serialVersionUID
of 0, and bump it with every structural change to your class which alters the serialized data (adding or removing non-transient fields).The built-in de-serialization mechanism (
in.defaultReadObject()
) will refuse to de-serialize from old versions of the data. But if you want to you can define your own readObject()-function which can read back old data. This custom code can then check theserialVersionUID
in order to know which version the data is in and decide how to de-serialize it. This versioning technique is useful if you store serialized data which survives several versions of your code.But storing serialized data for such a long time span is not very common. It is far more common to use the serialization mechanism to temporarily write data to for instance a cache or send it over the network to another program with the same version of the relevant parts of the codebase.
In this case you are not interested in maintaining backwards compatibility. You are only concerned with making sure that the code bases which are communicating indeed have the same versions of relevant classes. In order to facilitate such a check, you must maintain the
serialVersionUID
just like before and not forget to update it when making changes to your classes.If you do forget to update the field, you might end up with two different versions of a class with different structure but with the same
serialVersionUID
. If this happens, the default mechanism (in.defaultReadObject()
) will not detect any difference, and try to de-serialize incompatible data. Now you might end up with a cryptic runtime error or silent failure (null fields). These types of errors might be hard to find.So to help this usecase, the Java platform offers you a choice of not setting the
serialVersionUID
manually. Instead, a hash of the class structure will be generated at compile-time and used as id. This mechanism will make sure that you never have different class structures with the same id, and so you will not get these hard-to-trace runtime serialization failures mentioned above.But there is a backside to the auto-generated id strategy. Namely that the generated ids for the same class might differ between compilers (as mentioned by Jon Skeet above). So if you communicate serialized data between code compiled with different compilers, it is recommended to maintain the ids manually anyway.
And if you are backwards-compatible with your data like in the first use case mentioned, you also probably want to maintain the id yourself. This in order to get readable ids and have greater control over when and how they change.
If you will never need to serialize your objects to byte array and send/store them, then you don't need to worry about it. If you do, then you must consider your serialVersionUID since the deserializer of the object will match it to the version of object its classloader has. Read more about it in the Java Language Specification.
As for an example where the missing serialVersionUID might cause a problem:
I'm working on this Java EE application that is composed of a Web module that uses an
EJB
module. The web module calls theEJB
module remotely and passes aPOJO
that implementsSerializable
as an argument.This
POJO's
class was packaged inside the EJB jar and inside it's own jar in the WEB-INF/lib of the web module. They're actually the same class, but when I package the EJB module I unpack this POJO's jar to pack it together with the EJB module.The call to the
EJB
was failing with the Exception below because I hadn't declared itsserialVersionUID
:If you're serializing just because you have to serialize for the implementation's sake (who cares if you serialize for an HTTPSession, for instance...if it's stored or not, you probably don't care about de-serializing a form object), then you can ignore this.
If you're actually using serialization, it only matters if you plan on storing and retrieving objects using serialization directly. The serialVersionUID represents your class version, and you should increment it if the current version of your class is not backwards compatible with its previous version.
Most of the time, you will probably not use serialization directly. If this is the case, generate a default serializable uid by clicking the quick fix option and don't worry about it.
To understand the significance of field serialVersionUID, one should understand how Serialization/Deserialization works.
When a Serializable class object is serialized Java Runtime associates a serial version no.(called as serialVersionUID) with this serialized object. At the time when you deserialize this serialized object Java Runtime matches the serialVersionUID of serialized object with the serialVersionUID of the class. If both are equal then only it proceeds with the further process of deserialization else throws InvalidClassException.
So we conclude that to make Serialization/Deserialization process successful the serialVersionUID of serialized object must be equivalent to the serialVersionUID of the class. In case if programmer specifies the serialVersionUID value explicitly in the program then the same value will be associated with the serialized object and the class, irrespective of the serialization and deserialzation platform(for ex. serialization might be done on platform like windows by using sun or MS JVM and Deserialization might be on different platform Linux using Zing JVM).
But in case if serialVersionUID is not specified by programmer then while doing Serialization\DeSerialization of any object, Java runtime uses its own algorithm to calculate it. This serialVersionUID calculation algorithm varies from one JRE to another. It is also possible that the environment where the object is serialized is using one JRE (ex: SUN JVM) and the environment where deserialzation happens is using Linux Jvm(zing). In such cases serialVersionUID associated with serialized object will be different than the serialVersionUID of class calculated at deserialzation environment. In turn deserialization will not be successful. So to avoid such situations/issues programmer must always specify serialVersionUID of Serializable class.