Monday 6 January 2014

Serialization in Java

What is Serialization?

Serialization is the process of converting an object into a series of bytes, so that the object can be easily saved to persistent storage or streamed across a communication link. The byte stream can then be deserialised - converted into a replica of the original object.

What is java.io.Serializable?

Serializable is a marker interface just like  Cloneable interface. It does not have any methods to be implemented. Implementing this interface will allow an object to be serialized.

Example


package in.blogspot.iquestions;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializationExample {
    
    public static void main(String args[]) throws ClassNotFoundException{
        
        Employee employee = new Employee("Sam",18);
        
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\Aniket\\Desktop\\test.txt")));
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\Aniket\\Desktop\\test.txt")));
            System.out.println("Object before serialization : " + employee);
            oos.writeObject(employee);
            Employee employeeCopy = (Employee)ois.readObject();
            System.out.println("Object after deserialzation : " + employeeCopy);
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class Employee implements Serializable{
    
    private static final long serialVersionUID = 8414822319246756172L;
    String name;
    int age;
    
    public Employee(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Name is " + name + " and Age is " + age;
    }
    
}

Output :
Object before serialization : Name is Sam and Age is 18
Object after deserialzation : Name is Sam and Age is 18

What is use of serialVersionUID?

When you try your class to implement Serializable interface compiler will issue an warning.


Which clearly indicated you need something called serialVersionUID in your class. I use Eclipse and it gave me 3 quick fixes shown above.

  1. Add default serial version ID : Selecting this option will assign some default value hard coded in the IDE.
  2. Add generated serial version ID : This will generate a hash value depending on your variables/methods and use it in your class.
  3. The 3rd option is just a suppress warning to tell compiler you can ignore this warning.
This variable is private static final long . Default value option gives

private static final long serialVersionUID = 1L;

where as  generated one was as follows

private static final long serialVersionUID = 8414822319246756172L;

If you do not assign it then java compiler will generate it and normally it’s equal to hashCode of object.

This is about the variable but the main question still remains - Whats the need for it?

Well it is used to match the versions of the class. I will bring up this point again later but serialVersionUID is the only variable that is static and is serialized(state is stored) because static variables are not serialized. Just note this at the moment we will discuss it later. If these value on deserialization does not match exception InvalidClassException in thrown.

Are there any other ways to serialize an object other than Java serialization?

Answer to that would be Yes!
  1. For object serialization, instead of implementing the Serializable interface, a developer can implement the Externalizable interface, which extends Serializable. By implementing Externalizable, a developer is responsible for implementing the writeExternal() and readExternal() methods. As a result, a developer has sole control over reading and writing the serialized objects.
  2. XML serialization is an often-used approach for data interchange. This approach lags runtime performance when compared with Java serialization, both in terms of the size of the object and the processing time. With a speedier XML parser, the performance gap with respect to the processing time narrows. Nonetheless, XML serialization provides a more malleable solution when faced with changes in the serializable object.

What happens if the object to be serialized includes the references to other serializable objects?

If the object to be serialized includes the references to other objects whose class implements serializable then all those object’s state also will be saved as the part of the serialized state of the object in question. The whole object graph of the object to be serialized will be saved during serialization automatically provided all the objects included in the object’s graph are serializable.

 What happens if an object is serializable but it includes a reference to a non-serializable object?

If you try to serialize an object of a class which implements serializable, but the object includes a reference to an non-serializable class then a ‘NotSerializableException’ will be thrown at runtime.

Are the static variables saved as the part of serialization?

This is the question I was referring to earlier. Let us discuss this now. Recollect the purpose of Serialization. It is used to convert Object(with a state) to series if bytes and deserialization gives us back the exact same copy. The main purpose is to save the Object state and static variables do not form part of object state(rather they are part of Class state). So the answer is No! Static variables belong to the class and not to an object they are not the part of the state of the object so they are not saved as the part of serialized object. 

What is a transient variable?

 It has a very simple definition. Variables which you do not wish to save on serialization or which should not be a part of object state is to be defined as transient. These variables are not included in the process of serialization and are not the part of the object’s serialized state.

What will be the value of transient variable after de-serialization?

Transient variables will get default values[More details] on deserialization.  

Does the order in which the value of the transient variables and the state of the object using the defaultWriteObject() method are saved during serialization matter?

 Yes! As while restoring the object’s state the transient variables and the serializable variables that are stored must be restored in the same order in which they were saved. 

If a class is serializable but its superclass in not , what will be the state of the instance variables inherited  from super class after deserialization?

The values of the instance variables inherited from superclass will be reset to the values they were given during the original construction of the object as the non-serializable super-class constructor will run.

To serialize an array or a collection all the members of it must be serializable. True /False?

Arrays are Objects in Java and can be serialized like any other Object. Point to note here is that for an array to be serializable all of it's members must be serializable.

Suppose super class of a new class implement Serializable interface, how can you avoid new class to being serialized?

One of the tricky interview question in Serialization in Java. If Super Class of a Class already implements Serializable interface in Java then its already Serializable in Java, since you can not unimplemented an interface its not really possible to make it Non Serializable class but yes there is a way to avoid serialization of new class. To avoid java serialization you need to implement writeObject() and readObject() method in your Class and need to throw NotSerializableException from those method.

Note : Serialization doesn't write out the object a second time. It sees you're writing out an object that is already written out, and only writes out a reference to the object that previously was serialized.

For example see the code below -

public static void main(String args[]) throws FileNotFoundException, IOException, ClassNotFoundException
{
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("data.txt")));
    Human human = new Human();
    human.setAge(21);
    human.setName("Test");
    System.out.println("Human : " + human);
    oos.writeObject(human);
    human.setName("Test123");
    oos.writeObject(human);
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt")));
    Human newHuman1  = (Human)ois.readObject();
    System.out.println("newHuman1 :" + newHuman1);
    Human newHuman2  = (Human)ois.readObject();
    System.out.println("newHuman2 :" + newHuman2);
}


and it prints -

Human : Human [age=21, name=Test]
newHuman1 :Human [age=21, name=Test]
newHuman2 :Human [age=21, name=Test]

NOTE :  All classes get a serialVersionUID - one is generated by the serialization runtime if you haven't declared one. By declaring a serialVersionUID you're telling the serialization runtime, don't generate one because you know the serialized form of the classes is compatible with one built earlier.

 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.

Related  Links

t> UA-39527780-1 back to top