Manually defining a SerialVersionUID required?
This question already has an answer here:
SerialVersionUID
is used to check whether the version of class used for serializing and de-serializing is same or not across different JVM's.The default value generated by Serializable Runtime is sensitive to class details.So,although the classes loaded across different JVM may be compatible,but still you can get a false InvalidClassException .
Check the Javadoc:-
The serialization 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. 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. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:
*ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.*
I wanted to extend my comment but ran out of room.
nb These aren't my original thoughts, but rather from Joshua Bloch's Effective Java
Reason 1: Serialized objects can persist
Even small, otherwise trivial changes to the class will cause the JVM to generate a different ID. So when you try to deserialize an object serialized with an older but otherwise compatible class structure, the result is an InvalidClassException.
Changing something as innocuous as adding a convenience accessor to a class will force a different UID to be computed. Similarly, one of the things that influence the generated UID are private members. So not only are you restricted from changing the public facing API (which may be preferable), but you're also restricted from changing too drastically any private implementation details, for risk of causing a UID mismatch.
The other way to look at this is that by manually defining an UID, while you can ensure that the JVM will attempt to deserialize an object with its intended class, regardless of the changes to your class, you can also prevent the JVM from attempting to deserialize an object with its intended class (eg your new class is incompatible) by changing this UID.
Reason 2: Runtime computation is more expensive
Computed UIDs are computed at runtime. Manually specifying this field obviates this computation.
The central purpose of defining serialVersionUID
is to control serialization compatibility. As other answers and the documentation has noted, unless a specific value is declared, the value is computed from a variety of class characteristics, even ones that don't actually affect the serialized form, such as the signatures of public methods. If you don't provide a serialVersionUID
, and one or more of these characteristics of the class differs between serialization and deserialization, an InvalidClassException
will be thrown.
Now to the question of when one should or should not declare a serialVersionUID
.
If you care about serialization compatibility, you should almost always declare a serialVersionUID
. Doing this is the only possible way to evolve the class and have the serialized form be compatible with other versions of the class. You will probably also have to provide custom readObject
and writeObject
methods and use various mechanisms like readFields
, putFields
, and serialPersistentFields
to control the serialized format, and to cope with potential changes to the serialized format.
By "care about serialization compatibility", suppose you've serialized an object and have stored it in a file or database. Do you expect to have future versions of your system (with evolved versions of the classes) be able to read the stored serialized objects? Or, suppose you serialize objects and send them over a network to other applications that deserialize them. This happens in RMI, or it could happen if you develop your own network protocol that sends and receive serialized objects. If so, then on your network, can you have different versions of your application running in different places on the network, and do you expect them to be able to talk to each other successfully?
If any of the above are true, you care about serialization compatibility, and you need to declare serialVersionUID
.
There are times when you might care about serialization compatibility but when it doesn't make sense to declare a serialVersionUID
. One example is with anonymous inner classes. Such a class can be made serializable, but it's impractical to try to make it compatible, for several reasons. Anonymous inner classes have compiler-generated names that are implementation specific. They can also change across recompiles. AICs also contain references to their enclosing instance and references to any objects that might be captured from the local scope. All of these objects, and their transitive closure, become part of the serial form of an AIC. For these reasons it's a bad idea to serialize AICs, let alone try to achieve serial compatibility for them. In such cases, adding a serialVersionUID
is just a distraction. If you are tempted to serialize AICs, you probably want to restructure the code to serialize something else instead.
There might be times when you don't care about serialization compatibility of different class versions at all.
One example is if you have a closely coupled set of JVMs that are all sharing classes from the same classpath, and they're exchanging serialized objects. Since they are using the same actual classes, there can't be any incompatibility. Declaring a serialVersionUID
for classes in this case is useless busywork. In fact, doing so may conceal errors. In such a multi-JVM scheme, if there is a serialization compatibility error, that indicates some kind of configuration problem, since it means the JVMs are using different classes. You'd want that to be detected as soon as possible, and not declaring serialVersionUID
would cause an error to be manifested more quickly.
Another reason is that Serializable
is inherited, which may cause classes down the inheritance tree to become Serializable
even if they are never intended to be serialized. Again, declaring serialVersionUID
for such classes is useless busywork. There's no formal way for a class to reject its inheritance and "undeclare" serializability. Best practice, though, is for such classes to implement readObject
and writeObject
and for them to unconditionally throw an exception like InvalidObjectException
or NotSerializableException
.
Still another example is that your product requirements (or whatever) might simply decide not to care about serialization compatibility in certain cases or not at all. It's something that you might decide is just "not supported." The JDK itself has taken this approach. In general, most public, serializable classes in the JDK are constrained to be forward and backward serialization compatible. As such, all of these classes declare a serialVersionUID
and take care to deal with missing or added fields. However, some portions of the JDK, most notably AWT and Swing, are explicitly not serialization compatible across releases. Such classes have a disclaimer that warns of serial incompatibility, and instead of declaring a serialVersionUID
, these classes include an annotation @SuppressWarnings("serial")
to eliminate the warnings.
Bottom line is that it's a mistake to slavishly declare serialVersionUID
in every class that happens to inherit Serializable
. There are good reasons to declare it, and there are also good reasons not to declare it. You should decide explicitly.