I know that I can use serialVersionUID to control the version of classes. And I read that I can then add or remove fields and the class will still be compatible, it will just use default values.
When must I change the serialVersionUID?
Technically you can't prevent two classes from having the same serial version UID, much like you can't prevent two objects from having the same system hash code.
Simply put, we use the serialVersionUID attribute to remember versions of a Serializable class to verify that a loaded class and the serialized object are compatible. The serialVersionUID attributes of different classes are independent. Therefore, it is not necessary for different classes to have unique values.
Bullet Points. Defining a serialVersionUID field in a serializable class is not mandatory.
The serialization at runtime associates with each serializable class a version number called a serialVersionUID, which 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.
The value of the serialVersionUID field should ideally be changed when incompatible changes are made to the structure of the class. The complete list of incompatible changes is present in the Java Object Serialization Specification.
To expand further, incompatible changes to a class will prevent the deserialization mechanism from creating an instance of the object, because there is information in the stream that does not map to the current class definition.
The frequently-repeated mantra about changing the serialVersionUID
every time you change the class is complete and utter nonsense. See this Sun article which they republished on their site and which was migrated to the Oracle Technology Network after the acquisition.
You should change the serialVersionUID
only when you deliberately want to break compatibility with all existing serializations, or when your changes to the class are so radical that you have no choice - in which case you should really think several times about what it is that you are actually doing.
In all other cases you should bust your boiler trying to use custom readObject()/writeObject()
and/or writeReplace()/readResolve()
methods and/or serialFields
annotations so that you can continue to read objects from those existing serializations. Once you break that you are in for a major headache, indeed nightmare.
If you don't specify a serialVersionUID
field in your Serializable
classes, the Java compiler will specify one for you -- essentially it's a hash of the class name, interface names, methods, and fields of the class. Methods can be altered at any time, though, so if you need to change how a stored class is deserialized, you can override the readObject method. If you do specify the serialVersionUID
field in your code, though, the compiler won't override that even if you do make incompatible changes, which can result in an exception at runtime -- your IDE or compiler won't give you a warning. (EDIT -- thanks EJP) IDEs such as Eclipse can insert the compiler's UID for you, if you want to easily check how the compiler views certain changes.
If you make changes often, keep an old version of the disk file around to test deserialization with. You can write unit tests to try and read in the old file, and see if it works or if it's totally incompatible.
One caveat, I've personally experienced the pain that is working with Serializable
classes originally intended for long-term storage that were improperly designed. For example, storing GUI elements on disk rather than creating them when needed. Ask yourself if Serializable
is really the best way to save your data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With