Serialization and Deserialization in Java
Serialization and Deserialization in Java is an important programming concept. It is applicable to all major programming languages. In this chapter, we will try to understand this concept in the context of Java language. At the end of this chapter, we will be able to
- Conceptually know meaning of Serialization and Deserialization
- Understand the Java code to Serialization and Deserialization
Let us first define the two terms in Generic form, irrespective of any programming language.
What is Serialization?
Serialization is a process where you convert an Instance of a Class (Object of a class) into a Byte Stream. This Byte Stream can then be stored as a file on the disk or can also be sent to another computer via the network. Serialization can also be used to save the sate of Object when the program shuts down or hibernates. Once the state is saved on disk using Serialization, we can restore the state by DeSerializing the class from disk.
Let us try to visualize this using a small diagram. In this diagram, we will create a small class called Rectangle, which represents a real-life rectangle. Here is the code for the class
public class Rectangle {
private double height;
private double width;
public Rectangle(double height, double width)
{
this.height = height;
this.width = width;
}
public double Area()
{
return height * width;
}
public double Perimeter()
{
return 2 * (height + width);
}
}
Note: This class is not yet Serializable as per Java standards, let us ignore it for the time being.
Serialization process on the Rectangle class will look like this.
The encoding scheme that is used to convert from an Object of Class Rectangle to Byte stream is governed by the Serialization encoding standards mentioned here.
Serializable Interface
In Java, a Serializable object is an object which inherits from either of the two interfaces
Serializable interface is a marker interface. Which means that you do not have to implement any methods if your class derives from this interface. This is just a marker and the Java runtime, when trying to Serialize the class, will just check for the presence of this interface in the class. If Serializable interface is present in the class inheritance hierarchy, Java run time will take care of Serialization of the class.
On the other hand, the Externalizable interface is not a marker interface. If you derive from Externalizable interface you have to implement these two methods
- readExternal(ObjectInput input)
- writeExternal(ObjectOutput output)
We should inherit from Externalizable interface only when we want to overtake the Java's default serialization mechanism. If you want to use the default Java's serialization mechanism than you should inherit from Serializable interface only.
With this understanding, our Rectangle class will now inherit from Serializable interface.
public class Rectangle implements Serializable{
private double height;
private double width;
public Rectangle(double height, double width)
{
this.height = height;
this.width = width;
}
public double Area()
{
return height * width;
}
public double Perimeter()
{
return 2 * (height + width);
}
}
Serializing an Object in Java
Let us quickly take a look at the Serialization process in Java. In this process, we will perform these four steps
- We will create a new FileOutputStream of a file where we want to serialize the class
- We will then ObjectOutputStream on the FileOutputStream created in step 1
- We will then write the object into the ObjectOutputStream
- Finally, we will close all the stream objects to save properly write and terminate all streams.
Below is the code to perform the task. Pay attention to the comments that are mentioned above every line of code.
public static void SerializeToFile(Object classObject, String fileName)
{
try {
// Step 1: Open a file output stream to create a file object on disk.
// This file object will be used to write the serialized bytes of an object
FileOutputStream fileStream = new FileOutputStream(fileName);
// Step 2: Create a ObjectOutputStream, this class takes a files stream.
// This class is responsible for converting the Object of any type into
// a byte stream
ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
// Step 3: ObjectOutputStream.writeObject method takes an Object and
// converts it into a ByteStream. Then it writes the Byte stream into
// the file using the File stream that we created in step 1.
objectStream.writeObject(classObject);
// Step 4: Gracefully close the streams
objectStream.close();
fileStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args)
{
Rectangle rect = new Rectangle(18, 78);
SerializeToFile(rect, "rectSerialized");
}
When we run this program, it creates a file named "rectSerialized" in the root folder of the project. Just browse to that location and try to open the file using a notepad. Below image shows that
When you open this file you can see that it contains garbled characters. The contents are encoded and are not in human readable format. As shown in the image below.
This shows what exactly serialization means and how we can serialize an object in Java. This should also give you a practical understanding of the different steps involved in serialization process including the input and output results of the different steps.
Deserializing to an Object in Java
In the previous section, we learnt the Serialization converts a class instance into a byte stream which is then stored in a file on disk. Let us quickly take a look at the Deserialization process in Java, which is opposite of Serialization. In this process, we will read the Serialized byte stream from the file and convert it back into the Class instance representation. Here are the steps that we will follow.
- We will create a new FileInputStream to read the file which contains the serialized byte stream of the target class. Rectangle class in our case.
- We will then create an ObjectInputStream on the FileInputStream created in step 1
- We will then read the object using ObjectInputStream and store it in a variable of type Rectangle.
- Finally, we will close all the stream objects to save properly write and terminate all streams.
Below is the code to perform the task. Pay attention to the comments that are mentioned above every line of code.
public static Object DeSerializeFromFileToObject(String fileName)
{
try {
// Step 1: Create a file input stream to read the serialized content
// of rectangle class from the file
FileInputStream fileStream = new FileInputStream(new File(fileName));
// Step 2: Create an object stream from the file stream. So that the content
// of the file is converted to the Rectangle Object instance
ObjectInputStream objectStream = new ObjectInputStream(fileStream);
// Step 3: Read the content of the stream and convert it into object
Object deserializeObject = objectStream.readObject();
// Step 4: Close all the resources
objectStream.close();
fileStream.close();
// return the deserialized object
return deserializeObject;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void main(String[] args)
{
Rectangle rect = new Rectangle(18, 78);
SerializeToFile(rect, "rectSerialized");
Rectangle deSerializedRect = (Rectangle) DeSerializeFromFileToObject("rectSerialized");
System.out.println("Rect area is " + deSerializedRect.Area());
}
Just to verify that the original state of the Rectangle class is restored, we will debug the code and inspect deSerializedRect variable. The below image shows that the original state of (Height: 18 and Width: 78) Rectangle class is restored.
I hope that this tutorial clears the basic concept of Serialization and Deserialization in Java for you.