Serialization tutorial – Part I

What is serialization and how its performed?

Serialization is a mechanism through which we can save the state of an object by converting the object into a byte stream.

Serialized object (byte stream) can be transferred over network, persisted or saved into file/database.

We can deserialize the Serialized object (byte stream) and gets back the original object.

Let’s try to write a Java program to serialize an object.

Let’s create a package ‘Serialization’ and create a class ‘TestObject’ for creating an object to be serialized.

(Note: Package creation is not really required. You can even create classes in the default package as well, If you work with any IDE like eclipse.)

TestObject.java

package Serialization;

class TestObject {
       int number;
       String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

Now, Let’s create a class SerializeUtility which has methods for serializing and deserializing the given object, in the same package ‘Serialization’.

SerializeUtility.java

package Serialization;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
class SerializeUtility {

       public void serialize(Object obj) {
              // TODO: implement serialize logic
       }

       public Object deSerialize() {
              // TODO: implement deserialize logic
              return null;
       }
}

Now, let’s try to define the methods serialize() and deserialize() of class SerializeUtility.

To define serialize() method:

As we know, Serialization is a mechanism through which we can save the state of an object by converting the object into a byte stream. So first we need to convert the object into byte stream. After that lets save the converted bytestream into some file. To achieve this, we need to

1. Create an object of FileOutputStream class and pass the file location where we want to store the object byte stream.
FileOutputStream fos = new FileOutputStream(“testSerialization.txt”);

2. Create an object of ObjectOutputStream object and send the reference of FileOutPutStream object as parameter to ObjectOutputStream constructor.
ObjectOutputStream oos = new ObjectOutputStream( fos );

3. Pass the object to be serialized to the method writeObject() of ObjectOutputStream.
oos.writeObject ( obj );

This method writeObject() actually the one which starts the serialization process and the object is flattened (in this case to a file). We can close the streams at the end of the method and add expected exception catch blocks. You can take a look at the complete definition for serialize() below.

public void serialize (Object obj) {
              FileOutputStream fos = null;
              ObjectOutputStream oos = null;
              try {
                     fos = new FileOutputStream("testSerialization.txt");
                     oos = new ObjectOutputStream(fos);
                     oos.writeObject(obj);
              } catch (FileNotFoundException e) {
                     e.printStackTrace();
              } catch (IOException e) {
                     e.printStackTrace();
              }
              finally {
                     try {
                           oos.close();
                           fos.close();
                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              }
       }

To define deserialize() method:

As we know, deserialization is a process of getting back the original object from the saved object stream content. . To achieve this, we need to

1. Create an object of FileInputStream class and pass the file location where we stored the object byte stream file.
FileInputStream fis = new FileInputStream(“testSerialization.txt”);

2. Create an object of ObjectInputStream object and send the reference of FileInPutStream object as parameter to ObjectInputStream constructor.
ObjectInputStream ois = new ObjectInputStream( fis );

3. Return the object from the method readObject() of ObjectInputStream.
ois.readObject ();

This method readObject() reads the raw bytes that we previously persisted and creates a live object that is an exact replica of the original. Because readObject() can read any serializable object, a cast to the correct type is required. The class file must be accessible from the system in which the restoration occurs. In other words, the object’s class file and methods are not saved, only the object’s state is saved.

We can close the streams at the end of the method and add expected exception catch blocks. You can take a look at the complete definition for deserialize() below:

public Object deSerialize() {
              FileInputStream fis = null;
              ObjectInputStream ois = null;
              try {
                     fis = new FileInputStream("testSerialization.txt");
                     ois = new ObjectInputStream(fis);
                     return ois.readObject();
              } catch (FileNotFoundException e) {
                     e.printStackTrace();
              } catch (IOException e) {
                     e.printStackTrace();
              } catch (ClassNotFoundException e) {
                     e.printStackTrace();
              }
              finally {
                     try {
                           ois.close();
                           fis.close();
                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              }
              return null;
       }

You can take a look at the complete class definition for ‘SerializeUtility’ below:

SerializeUtility.java

package Serialization;

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

class SerializeUtility {

       public void serialize(Object obj) {
              FileOutputStream fos = null;
              ObjectOutputStream oos = null;
              try {
                     fos = new FileOutputStream("testSerialization.txt");
                     oos = new ObjectOutputStream(fos);
                     oos.writeObject(obj);
              } catch (FileNotFoundException e) {
                     e.printStackTrace();
              } catch (IOException e) {
                     e.printStackTrace();
              }
              finally {
                     try {
                           oos.close();
                           fos.close();
                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              }
       }

       public Object deSerialize() {
              FileInputStream fis = null;
              ObjectInputStream ois = null;
              try {
                     fis = new FileInputStream("testSerialization.txt");
                     ois = new ObjectInputStream(fis);
                     return ois.readObject();
              } catch (FileNotFoundException e) {
                     e.printStackTrace();
              } catch (IOException e) {
                     e.printStackTrace();
              } catch (ClassNotFoundException e) {
                     e.printStackTrace();
              }
              finally {
                     try {
                           ois.close();
                           fis.close();
                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              }
              return null;
       }
}

If we are using Java 7 or higher version JDK then we can use Java 7 features like try-resource statement and multi-catch block. So our code will be looking like below:

package Serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

class SerializeUtility {

       public void serialize(Object obj) {
              try (
                  FileOutputStream fos = new FileOutputStream("testSerialization.txt");
                  ObjectOutputStream oos = new ObjectOutputStream(fos);
                  )
              {
                  oos.writeObject(obj);
              } catch (IOException e) {
                     e.printStackTrace();
              }
       }

       public Object deSerialize() {
              try (
                  FileInputStream fis = new FileInputStream("testSerialization.txt");
                  ObjectInputStream ois = new ObjectInputStream(fis);
                  )
              {
                  return ois.readObject();
              } catch (ClassNotFoundException | IOException e) {
                     e.printStackTrace();
              }
              return null;
       }
}

Now, lets serialize and deserialize the TestObject’s object with the SerializeUtility’s methods serialize() and deserialize(). For that we need to create a class SerializationTest in the same package ‘Serialization’ and have an TestObject instance and call serialize() of SerializeUtility in the main method as shown below, similar can be done for deserialize.

SerializationTest.java

package Serialization;

public class SerializationTest {
       public static void main(String[] args) {
              TestObject tObj1 = new TestObject(10, "TestSerialization");
              SerializeUtility utility = new SerializeUtility();

              // serialization
              utility.serialize(tObj1);
              // deserialization
              TestObject tObj2 = (TestObject)utility.deSerialize();

              System.out.println("Number: " + tObj2.number);
              System.out.println("Name: " + tObj2.name);
       }
}

Don’t try to run this class ‘SerializationTest’. If you do so, you will get java.io.NotSerializableException: TestObject. As JVM sees that the object of ‘TestObject’ class is not eligible for serialization and hence throws the exception. So, to make any instance of the class ‘TestObject’ eligible for serialize, ‘TestObject’ class needs to implement Serializable interface as shown below.

TestObject.java

package Serialization;

import java.io.Serializable;

public class TestObject implements Serializable {
       int number;
       String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

Serializable interface is a marker interface means contains no fields or methods within it and is used to indicate to JVM, that any instance of this class is ready to be serialized.

If you compile all classes which we created so far (SerializationTest.java, SerializationUtility.java and TestObject.java) and run SerializationTest.java (which contains main() method) , you will get the following output:

Number: 10

Name: TestSerialization

If a parent class is Serializable, Can we serialize its child classes ?

Let us create a child class TestObjectChild to TestObject by extending it like below:

TestObjectChild.java

package Serialization;

public class TestObjectChild extends TestObject {
       String childName;
       TestObjectChild(int i, String s1, String s2) {
              super(i, s1);
              childName = s2;
       }
}

Though child class does not have the “implements Serializable” in its declaration but still child class implements Serializable interface implicitly as its parent class TestObject implements Serializable interface.

Now let us try to serialize the child object TestObjectChild like below:

SerializationTest.java

package Serialization;

public class SerializationTest {
       public static void main(String[] args) {
              TestObjectChild tObj1 = new TestObjectChild(10, "TestSerialization", "TestObjectChild");
              SerializeUtility utility = new SerializeUtility();

              // serialization
              utility.serialize(tObj1);
              // deserialization
              TestObjectChild tObj2 = (TestObjectChild)utility.deSerialize();

              System.out.println("Number: " + tObj2.number);
              System.out.println("Name: " + tObj2.name);
              System.out.println("ChildName: " + tObj2.childName);
       }
}

If you compile all classes which we created so far (SerializationTest.java, SerializationUtility.java, TestObject.java and TestObjectChild.java) and run SerializationTest.java (which contains main() method) , you will get the following output:

Number: 10
Name: TestSerialization
ChildName: TestObjectChild

 

If a parent class is Serializable, How to avoid child class from being serialized ?

Since parent class is Serializable, its child classes are also Serializable implicitly and hence eligible for Serialization process.

But If we don’t want child classes to be serialized then we can define below method in the child classes

private void writeObject(ObjectOutputStream oos) throws IOException {
    throw new NotSerializableException();
  }

 

We can define the above method in TestObjectChild class like below:

TestObjectChild.java

package Serialization;

import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectOutputStream;

public class TestObjectChild extends TestObject {
  String childName;

  TestObjectChild(int i, String s1, String s2) {
    super(i, s1);
    childName = s2;
  }

  private void writeObject(ObjectOutputStream oos) throws IOException {
    throw new NotSerializableException();
  }
}

If we try to serialize the TestObjectChild object with the above SerializationTest.java, then java.io.NotSerializableException will be thrown like below:

java.io.NotSerializableException
	at Serialization.TestObjectChild.writeObject(TestObjectChild.java:15)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at Serialization.SerializeUtility.serialize(SerializeUtility.java:17)
	at Serialization.SerializationTest.main(SerializationTest.java:9)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
	at java.io.ObjectInputStream.readSerialData(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at Serialization.SerializeUtility.deSerialize(SerializeUtility.java:29)
	at Serialization.SerializationTest.main(SerializationTest.java:11)
Caused by: java.io.NotSerializableException
	at Serialization.TestObjectChild.writeObject(TestObjectChild.java:15)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at Serialization.SerializeUtility.serialize(SerializeUtility.java:17)
	at Serialization.SerializationTest.main(SerializationTest.java:9)
Exception in thread "main" java.lang.NullPointerException
	at Serialization.SerializationTest.main(SerializationTest.java:13)

We will get to know about this writeObject() shortly in our next section.

If parent class is not Serializable but its child class is Serializable then what will be the state of the instance variables inherited from super class after deserialization?

Now let us make TestObject class not implementing Serialzable interface and make TestObjectChild class implementing Serializable interface like below:

 TestObject.java

package Serialization;

public class TestObject {
       int number;
       String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

TestObjectChild.java

package Serialization;

import java.io.Serializable;

public class TestObjectChild extends TestObject implements Serializable {
       String childName;
       TestObjectChild(int i, String s1, String s2) {
              super(i, s1);
              childName = s2;
       }
}

If you compile all classes which we created so far (SerializationTest.java, SerializationUtility.java, TestObject.java and TestObjectChild.java) and run SerializationTest.java (which contains main() method) , we will get the following error:

java.io.InvalidClassException: Serialization.TestObjectChild; no valid constructor
	at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
	at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at Serialization.SerializeUtility.deSerialize(SerializeUtility.java:29)
	at Serialization.SerializationTest.main(SerializationTest.java:11)
Exception in thread "main" java.lang.NullPointerException
	at Serialization.SerializationTest.main(SerializationTest.java:13)

Since TestObjectChild object inherit the properties number and name from its parent object TestObject, To initialize them during deserialization Java calls the public no-argument constructor of parent class TestObject. Since there is no public no-argument constructor defined in the parent class TestObject, Java throws the error at run time.

If we provide a public no-argument constructor in TestObject like below and re-run our SerializationTest.java then we get the fields with their initialized values like below:

 TestObject.java

package Serialization;

public class TestObject {
       int number;
       String name;

       public TestObject() {
         number = 100;
         name = "default_name";
       }

       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

If you compile all classes which we created so far (SerializationTest.java, SerializationUtility.java, TestObject.java and TestObjectChild.java) and run SerializationTest.java (which contains main() method) , we will get the following output:

Number: 100
Name: default_name
ChildName: TestObjectChild

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s