SerialVersionUID is one among the favorite topics in Java interview. Its important for Java programmer to understand its concept, not only for the interview but to use serialization in java. We will start by understanding what is SerialVersionUID and how it is generated, and then move forward to see some code examples.
SerialVersionUID
SerialVersionUID is used to ensure
that during deserialization the same class (that was used during serialize
process) is loaded.
Syntax:
ANY-ACCESS-MODIFIER final
static long serialVersionUID = < value>
serialVersionUID is
a static final field. You can assign any number of your choice to it.
How serialVersionUID is generated?
During object serialization, the default Java
serialization mechanism writes the metadata about the object, which includes
the class name, field names and types, and superclass. This class definition is
stored as a part of the serialized object. This stored metadata enables the
deserialization process to reconstitute the objects and map the stream data
into the class attributes with the appropriate type.
Every time an object is serialized the java serialization mechanism
automatically computes a hash value, if you do not provide one in source. ObjectStreamClass's computeSerialVersionUID()
method passes the class name, sorted member names, modifiers, and interfaces to
the secure hash algorithm (SHA), which returns a hash value. This value is the serialVersionUID of the class, also
called suid.
So when the serialize object is retrieved, the JVM first evaluates the suid of
the serialized class and compares the suid value with the one
of the object. If the suid values match then the object is said to be
compatible with the class and hence it is de-serialized. If not InvalidClassException exception
is thrown.
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 produce different
serialVersionUID in different environments.
Demonstrate serialVersionUID
Initial class to be
serialized has a serialVersionUID as 1L.
import java.io.Serializable;
public class Lion implements Serializable {
private static final long serialVersionUID = 1L;
private String sound;
public Lion(String sound) {
this.sound = sound;
}
public String getSound() {
return sound;
}
}
Test serialVersionUID:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerialVersionUIDTest {
public static void main(String args[]) throws IOException, ClassNotFoundException {
Lion leo = new Lion("roar");
// serialize
System.out.println("Serialization done.");
FileOutputStream fos = new FileOutputStream("serial.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(leo);
// deserialize
FileInputStream fis = new FileInputStream("serial.out");
ObjectInputStream ois = new ObjectInputStream(fis);
Lion deserializedObj = (Lion) ois.readObject();
System.out.println("DeSerialization done. Lion: " + deserializedObj.getSound());
}
}
Output:
Serialization done.
DeSerialization done. Lion: roar
Now change serialVersionUID
to 2L in Lion class.
private static final long serialVersionUID = 2L;
Comment the “serialize”
block (4 lines of code) in SerialVersionUIDTest. Now run it and you will get
the following exception.
- Serialized Lion
with serialVersionUID with 1L.
- Changed
serialVersionUID to 2L and compiled and loaded the class.
- Deserialize the
already serialized object and load it with the latest class.
- We get
exception as serialVersionUID is not matching.
Exception in thread "main" java.io.InvalidClassException: Lion; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerialVersionUIDTest.main(SerialVersionUIDTest.java:21)
Compatible or Incompatible changes to a serializable class
Simple
Examples of compatible changes are:
- Addition of a new field or class will not affect serialization, since any new data in the stream is simply ignored by older versions. The newly added field will be set to its default values when the object of an older version of the class is un-marshalled.
- The access modifiers change (like private, public, protected or default) is compatible since they are not reflected in the serialized object stream.
- Changing a transient field to a non-transient field is compatible change since it is similar to adding a field.
- Changing a static field to a non-static field is compatible change since it is also similar to adding a field.
Some Simple Examples of incompatible changes are:
- Changing implementation from Serializable to Externalizable interface cannot be done since this will result in the creation of an incompatible object stream.
- Deleting an existing Serializable fields will cause a problem.
- Changing a non-transient field to a transient field is incompatible change since it is similar to deleting a field.
- Changing a non-static field to a static field is incompatible change since it is also similar to deleting a field.
- Changing the type of an attribute within a class would be incompatible, since this would cause a failure when attempting to read and convert the original field into the new field.
- Changing the package of class is incompatible. Since the fully-qualified class name is written as part of the object byte stream.
If no suid is present, inspite of making compatible changes, JVM
generates new suid, thus resulting
in an exception if prior release version object is used.
The only way to get rid of the
exception is to recompile and deploy the application again. If we explicitly mention the suid, then if any of the mentioned
compatible changes are made the class need not to be recompiled. But for
incompatible changes there is no other way than to compile again.
Hope you liked the post. Connect at +Java Territory to stay tuned with latest updates.
Hope you liked the post. Connect at +Java Territory to stay tuned with latest updates.
Very well explained...
ReplyDelete