Hi Friends,
In this post, I'm going to explain concept and process of Deserialization.
Deserialization is a
process by which the object previously serialized is reconstructed back into
it’s original form. The input to the deserialization process is the stream of
bytes which we get over the other end of network or we simply read it from the file
system or database.
Question: What is written in
this stream of bytes?
Answer: It contains all
the information about the instance which was serialized by serialization
process. This information includes class’s meta data, type information of
instance fields and values of instance fields as well.
This same information is
needed when object is reconstructed back to a new object instance.
While deserializing an
object, the JVM reads its class metadata from the stream of
bytes which specifies whether the class of an object implements either Serializable or Externalizable
interface.
Note that for the
deserialization to happen seamlessly, the byte code of a class, whose object is being deserialized, must be
present within the JVM performing
deserialization.Otherwise, the ClassNotFoundException is
thrown.
During deserialization,
JVM creates object without calling constructor.
Note: In deserialization
process, all the parent classes of instance should be serializable and if any
super class in hierarchy is not serializable then it must have a default
constructor.
So while
deserialization, the super most class is searched first until any
non-serializable class is found. If all super classes are serializable then JVM
end up reaching Object class itself and create an instance of Object class
first.If in between searching the super classes, any class is found
non-serializable then it’s default constructor will be used to allocate an
instance in memory.
If any super class of
instance to be deserialized is non-serializable and also doesn’t have a default
constructor then the ’NotSerializableException’ is thrown by JVM.
Also, before continuing
with the object reconstruction, the JVM checks to see if the serialVersionUID mentioned
in the byte stream matches the serialVersionUID of the class of that object. If
it doesn’t match then the ‘InvalidClassException’ is thrown.
So, till now we got the
instance located in memory using one of superclass’s default constructor. Note
that after this no constructor will be called for any class. After executing
super class constructor, JVM read the byte stream and use instance’s meta data
to set type information and other meta information of instance.
After the blank instance
is created, JVM first set it’s static fields and then invokes
the default readObject() method [if it’s not overridden, otherwise
overridden method will be called] internally which is responsible for setting
the values from byte stream to blank instance.
After the readObject()
method is completed, the deserialization process is done and you are ready to work with new deserialized
instance.
What is the use of
serialVersionUID?
- Java Runtime automatically associates with each 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 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 with name “serialVersionUID"that must be of type static, final and long.
- Any Access Modifier static final long serialVersionUID = 42L;
- If this ID is not specified explicitly, then Java runtime associates default UID.
- It is highly recommended that we should explicitly define a serialVersionUID, as default UID is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization.
- serialVersionUID represents the class version and we should increment it if the current version of our class is not backwards compatible with its previous version.
- Automatically generated UID is generated based on class name, its implemented interfaces and all its public and protected members. Changing any of these in any way will change the serialVersionUID.
- If later, we need to make changes in new class in such a way that it provides backward compatibility to older version of classes, then we should use java tool serialver to generate serialVersionUID on the old class, and explicitly set that on the new class.
- If we make changes in some fields of class and forget to change the UID field, then the default mechanism (in.defaultReadObject()) will not detect any difference, and try to deserialize incompatible data. That can lead to hard to find errors.
Fast Facts:
transient and static
fields are ignored in serialization. After deserialization, transient fields
and non-final static data will be null. Final static fields still have values
since they are part of the class data.
ObjectOutputStream and
ObjectInputStream are used in serialization and deserialization.
During serialization,
you need to handle IOException and during deserialization, you need to handle IOException and ClassNotFoundException. So the deserialized
class type must be in the class path.
Serialization and
deserialization can be used for copying and cloning objects. It is slower than
regular clone, but can produce a deep copy very easily.
No comments:
Post a Comment