Serialization in Java - Javastudypoint

Tuesday, January 22, 2019

Serialization in Java


Serialization in Java is a technique of converting the state of an object into a byte stream. By using FileOutputStream and ObjectOutputStream classes we can achieve Serialization in Java. The ObjectOutputStream take an object and convert into binary data and FileOutputStream is used to write the binary data into a file. The writeObject() method of ObjectOutputStream is used to serialize our object. 



Deserialization in Java is a mechanism of rebuilding the object from a byte stream or we can say that it is a reverse process of serialization. By using FileInputStream and ObjectInputStream classes we can achieve Deserialization in Java. The FileInputStream is used to read binary data from a file and ObjectInputStream is responsible for reading objects from a stream. The readObject() method of ObjectInputStream is used to deserialize our object.

Example of Serialization in Java:

The following program illustrates how to use serialization and deserialization in java. We can serialize only serializable objects. An object is said to be serializable if and only if a corresponding class implements the Serializable interface. Serializable interface present in a java.io package it doesn't contain any method. It is a marker interface. If we are trying to serialize non-serializable object then we will get a runtime exception saying NotSerializableException. 
Serialization in Java
import java.io.*;
class Example implements Serializable
{
int a = 10;
int b = 20;
}
class SerializationDemo
{
public static void main(String args []) throws Exception
{
Example obj1 = new Example();

// Serialization
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");

// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");

ObjectInputStream ois = new ObjectInputStream(fis);


// Method for deserialize our object

Example obj2 = (Example) oos.readObject();

fis.close();

ois.close();

System.out.println("The value of a is: "  + obj2.a);
System.out.println("The value of b is: "  + obj2.b);
}
}

Output:
Serialization Done!
The value of a is:   10
The value of b is:   20

Transient Keyword in Java:

Transient is a keyword in Java which is used in Serialization. It is applicable only for variables. At the time of serialization if you don't want to serialize the value of a particular object for security concern then we should go for the transient keyword in Java.

At the time of serialization when we declared a variable as transient JVM ignore the original value of a transient variable and set a default value to the file. Hence we can say that transient means not to serialize.

Example of Java Transient Keyword:

In this example, we have created two variables name and password. The password variable of an example class declared as transient, so it values will not be serialized. Therefore JVM ignores the original value of a transient variable and set a default value to the file. 
import java.io.*;
class Example implements Serializable
{
String name = "Amit";

// declared variable as transient
transient int password = 12345;
}
class SerializationDemo
{
public static void main(String args []) throws Exception
{
Example obj1 = new Example();

// Serialization
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");

// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);


// Method for deserialize our object

Example obj2 = (Example) oos.readObject();

fis.close();

ois.close();

System.out.println("User name is: ",  + obj2.name);
System.out.println("User password  is: ", + obj2.password);
}
}

Output:
Serialization Done!
The name of a user is:    Amit
The password of a user is: 0

Object Graph in Serialization:

Whenever we are serializing an object the set of all object that contains the reference from that object will be serialized automatically. This group of a set is known as Object Graph. In Object Graph every object should be serializable. If at least one object is non-serializable then we will get a runtime exception saying NotSerializableException. Let's understand this with an example.
Read: What is an exception and how to handle it

Example of Object Graph in Serialization:

In this example, whenever we are serializing Serialize1 class object automatically Serialize2 and Serialize3 class objects will be serialized, because these are the part of object graph of Serialize1 object. Among Serialize1, Serialize2, and Serialize3 class if at least one object is not-serializable then we will get a runtime exception.
import java.io.*;
class Serialize1 implements Serializable
{

// class Serialize1 contains refrence to 
// object of class Serialize2
Serialize2  s2= new Serialize2();
}
class Serialize2 implements Serializable
{

// class Serialize2 contains refrence to 
// object of class Serialize3
Serialize3  s3= new Serialize3();
}

// A refrence of this class present
// in class Serialize2
class Serialize3 implements Serializable
{
int a = 10;
int b = 20;
}
class SerializationDemo
{
public static void main(String args []) throws Exception
{

//creating an object of class Serialize1
Serialize1 s1 =new Serialize1();
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for serialize our object
oos.writeObject(s1);
fos.close();
oos.close();
System.out.println("Serialization Done!");

// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserialize our object

Serialize1 sbj = (Serialize1) ois.readObject();

fis.close();

ois.close();

// Printing the value of a and b after serialization
System.out.println(" The value of a after deserialization is: " + sbj.s2.s3.a);
System.out.println(" The value of b after deserialization is: " + sbj.s2.s3.b);
}
}

Output:
Serialization Done!
The value of a after deserialization is: 10
The value of b after deserialization is: 20


Customized Serialization in Java:

In the normal Serialization, everything takes care by the JVM so that the programmer roles is very very less. Sometime we may not satisfy with default Serialization then we should go for Customized Serialization in Java.

Need of Customized Serialization in Java:

In default Serialization, because of the transient keyword, there may be a chance of loss of information to recover this loss of information then we should go for Customized Serialization in Java.
Serialization in Java
Let's take a simple example to understand this, In this example before Serialization Example, class object can provide a proper username and password. But after De-Serialization Example class object can provide the only username not password this is due to the transient keyword 
import java.io.*;
class Example implements Serializable
{
String name = "Amit";

// declared variable as transient
transient int password = 12345;
}
class SerializationDemo
{
public static void main(String args []) throws Exception
{
Example obj1 = new Example();

// printing username and password 
// before Serialization
System.out.println("The user name is: " +obj1.name);
System.out.println("The password is: " +obj1.password);

// Serialization
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");

// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
Example obj2 = (Example) oos.readObject();
fis.close();
ois.close();
System.out.println("User name is  ",  + obj2.name);
System.out.println("User password  is: ",  + obj2.password);
}
}


Output:
The name of a user is:    Amit
The password of a user is: 12345  
Serialization Done!
The name of a user is:    Amit
The password of a user is: 0    // lose of information.

Example of Customized Serialization:

We can implement Customized Serialization in Java by using the following two methods:
1. private void writeObject(ObjectOutputStream oos) throws Exception:
This method will be executed automatically at the time of object Serialization. If you have to perform any activity during Serialization, it must be defined only in this method.
2. private void readObject(ObjectInputStream ois) throws Exception
This method will be executed automatically at the time of object deserialization. If you have to perform any activity during deserialization, it must be defined only in this method.  
The above methods are also known as the Callback methods because these methods will be executed automatically by the JVM. While performing Customized Serialization, we have to define the above two methods in that class.
import java.io.*;
class Example implements Serializable
{
String name = "Amit";

// declared variable as transient
transient String password = "java";

private void writeObject(ObjectOutputStream oos) throws Exception
{

// to perform default serialization of Example object
oos.defaultWriteObject();

// encrypted password
String epwd = "123"+password;

// To write encrypted password to the file
oos.writeObject(epwd);
}

private void readObject(ObjectInputStream ois) throws Exception
{
// to perform default deserialization of Example object
ois.defaultReadObject();

// Reading encrypted password
String epwd = (String)ois.readObject();

// perform decryption and assign decrypted
// password in to the original password
password = epwd.substring(3);
}
}
class SerializationDemo
{
public static void main(String args []) throws Exception
{
Example obj1 = new Example();
// printing username and password 
// before Serialization

System.out.println("The user name is: " +obj1.name);
System.out.println("The password is: " +obj1.password);

// Serialization
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");

// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
Example obj2 = (Example) oos.readObject();
fis.close();
ois.close();
System.out.println("User name is: "  + obj2.name);
System.out.println("User password is: "  + obj2.password);
}
}

To understand the above example see in the image given below:


Serialization in Java
Output:
User name is:      Amit
User password is: Java

Inheritance in Java Serialization?

Serialization in Java is a technique of converting the state of an object into a byte stream. Whereas deserialization in Java is a mechanism of rebuilding the object from a byte stream or we can say that it is a reverse process of serialization. Here we have discussed two cases of Serialization with respect to inheritance.
Read: What is Inheritance in Java - A complete tutorial

Case1: if a parent class is serializable but child class is not serializable.

If the parent class is serializable then by default every child class is serializable. You won't need to implement a serializable interface in the child class. Hence, even though the child class doesn't implement serializable if parent class implement serializable then we can serialize child class object. Let's understand this with an example.
Serialization in Java
import java.io.*;

// parent class implements
// serializable interface.
class A implements Serializable
{
int a = 10;
}

// child class  doesn't implements
// serializable interface.
class B extends A
{
int b = 20;
}

class SerializationDemo
{
public static void main(String args []) throws Exception
{
B obj1 = new B();
System.out.println("The value of A is: " +obj1.a);
System.out.println("The value of B is: " +obj1.b);
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");


FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
B objt2 = (B) ois.readObject();
fis.close();
ois.close();
System.out.println("The value of A after deserialization is: ",  + objt2.a);
System.out.println(" The value of B after deserialization is:",  + objt2.b);
}
}

Output:
The value of A is: 10
The value of B is: 20
Serialization Done!
The value of A after deserialization is: 10
The value of B after deserialization is:  20

Case2: if a parent class is not serializable but child class is serializable.

Even though a parent class doesn't implement the serializable interface, we can serialize child class object if child class itself implements the serializable interface. So we can say that to serialize child class object, parent class not need to be serialized. But now a question arises what happens with the parent class instances during Serialization in this case. Let's understand this with the procedure given below:
1. At the time of Serialization, if any instance variable inheriting from non-serializable parent class then JVM ignore its original value and save default value to the file.
2. At the time of deserialization, if any parent class is non-serializable then JVM will execute instance control flow in that non-serializable parent class. To execute instance control flow in a non-serializable parent class, JVM will always invoke no argument constructor (default constructor) of that class. Hence every non-serializable parent class must contain no argument constructor (default constructor), otherwise, we will get a runtime exception.


Serialization in Java

import java.io.*;

// parent class doesn't implements
// serializable interface.
class A 
{
int a = 10;

// default constructor
public A()
{
System.out.println(" A's class constructor is called!");
}
}

// child class implements
// serializable interface.
class B extends A implements Serializable
{
int b = 20;

// default constructor
public B()
{
System.out.println(" B's class constructor is called!");
}
}

class SerializationDemo
{
public static void main(String args []) throws Exception
{
B obj1 = new B();
obj1.a = 777;
obj1.b = 888;
System.out.println("The value of A is: " +obj1.a);
System.out.println("The value of B is: " +obj1.b);
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();
System.out.println("Serialization Done!");
System.out.println("De-serialization started!");


FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
B objt2 = (B) ois.readObject();
fis.close();
ois.close();
System.out.println(" The value of A after deserialization is: "  + objt2.a);
System.out.println(" The value of B after deserialization is: "  + objt2.b);
}
}

Output:
A's class constructor is called!
B's class constructor is called!
The value of A is: 777
The value of B is: 888
Serialization Done!
De-serialization started!
The value of A after deserialization is: 10

The value of B after deserialization is: 888


Externalization in Java:

In Serialization total object is saved to the file and it is not possible to save part of an object which creates a performance problem. To overcome this problem we should go for Externalization in Java.
The main advantage of Externalization over Serialization is we can save either total object or part of an object so that the relative performance will be improved.





An object is said to be externalizable if and only if a corresponding class implements the Externalizable interface. Externalizable is an interface which is present in java.io. package and it is the child interface of Serializable. The Externalizable interface contains two methods.
1. public void writeExternal(ObjectOutput out) throws IOException:

This method will be executed automatically at the time of object Serialization. In this method, we have to write the code to save the required variables to a file.
2. public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException:
This method will be executed automatically at the time of object deserialization. In this method, we have to write the code to read the required variables from a file and assign to the current object.
At the time of deserialization, JVM will create a separate new object by executing default constructor on that object readExternal() method will be executed.
Hence if a class implements Externalizable interface then it should be compulsory for that class contains no-arg constructor (default constructor). Otherwise, we will get a runtime exception saying InvalidClassException

Externalization Example in Java:

Case 1: When the class doesn't contain no-arg constructor (default constructor). It will give InvalidClassException.
import java.io.*;
class Student implements Externalizable
{
String name;
int id;
String address;

// parameterized constructor
public Student(String name, int id, String address)
{
this.name= name;
this.id = id;
this.address = address;
}public void writeExternal(ObjectOutput out) throws IOException
{

// variables saved into the file.
out.writeObject(name);
out.writeInt(id);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{

// Read the variables from a file
name = (String)in.readObject();
id = in.readInt();
}
}
public class ExternalizationDemo
{
public static void main(String args []) throws Exception
{
Student obj1 = new Student("Amit", 101, "India");

// Serialize the Student
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();

// deserialize the Student
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
Student obj2 = (Student) ois.readObject();
fis.close();
ois.close();
System.out.println("The student name is:" +obj2.name);
System.out.println("The student Id is:" +obj2.id);
System.out.println("The student address is:" +obj2.address);
}
}

Output:
Serialization in Java

Case 2: When a class contains no-arg constructor (default constructor). 
import java.io.*;
class Student implements Externalizable
{
String name;
int id;
String address;

// default constructor
public Student()
{
System.out.println("The Default constructor is called!");
}
public Student(String name, int id, String address)
{
this.name= name;
this.id = id;
this.address = address;
}public void writeExternal(ObjectOutput out) throws IOException
{

// variables saved into the file.
out.writeObject(name);
out.writeInt(id);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{

// Read the variables from a file
name = (String)in.readObject();
id = in.readInt();
}
}
public class ExternalizationDemo
{
public static void main(String args []) throws Exception
{
Student obj1 = new Student("Amit", 101, "India");

// Serialize the Student
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

// Method for Serialize our object
oos.writeObject(obj1);
fos.close();
oos.close();

// deserialize the Student
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);

// Method for deserializing our object
Student obj2 = (Student) ois.readObject();
fis.close();
ois.close();
System.out.println("The student name is:" +obj2.name);
System.out.println("The student Id is:" +obj2.id);
System.out.println("The student address is:" +obj2.address);
}
}

Output:
The default constructor is called!
The student name is: Amit
The student Id is:  101
The student address is: null

 Serialization vs Externalization in Java:

1. Serialization is meant for default serialization while Externalization is meant for customized serialization.

2. In serialization, everything takes care by JVM and programmer role is very less while in Externalization everything takes care by the programmer so the programmer role is very important.

3. In serialization, we can always save the total object into a file and it is not possible to save part of the object while in Externalization we can save either total object or part of the object.

4. In the case of serialization, performance is low while in case of Externalization performance is high.

5. For object serialization, we must need to implement the serializable interface and it doesn't contain any method so it is a marker interface while for object externalization, we must need to implement the Externalizable interface and it contains two methods so it is not a marker interface.

6. Serialization is the best choice if we want to save the total object into a file while Externalization is the best choice if we want to save either total or part of the object into a file.

7. Serializable implemented class not required to contain the no-arg constructor while Externalizable implemented class should compulsory contain the no-arg constructor otherwise we will get a runtime exception.

8. In serialization,  transient keyword play a major role while in externalization transient keyword won't play any role.



SerialVersionUID in Java:

Before talking about SerialVersionUID, let's discuss a little bit about Serialization and Deserialization after this we will discuss the role of SerialVersionUID.
In Serialization and Deserialization, both sender and receiver need not be same and not be from the same location and not to use the same machine ie. person may be different, the location may be different, machine or system may be different then SerialVersionUID comes in picture.



For example: Suppose a person who is in Delhi and another person who is in Mumbai both are trying to perform Serialization and Deserialization respectively.

In this case, to authenticate that the receiver who is in Mumbai is the authenticated person or not, JVM creates a unique id this id is known as SerialVersionUID.

At the time of Deserialization, the receiver side JVM will compare object unique id with the local .class unique id. If both are matched then only deserialization will be performed otherwise receiver unable to deserialize and we will get a runtime exception InvalidClassException.

The sender side JVM is responsible to generate this unique id this unique id is default SerialVersionUID. There are several problems are there if we are depending on default SerialVersionUID generated by JVM.

1. Both sender and receiver should use same JVM, if there is any mismatch in JVM version then the receiver is unable to deserialize because of different SerialVersionUID and in this case, we will get a runtime exception InvalidClassException.

2. Both the sender and receiver should use the same .class file version. After Serialization if we changed the .class file at receiver side then we cannot perform deserialization because of mismatch in SerialVersionUID's of the local class of receiver and serialized the object and we will get a runtime exception.


3. The sender side JVM is responsible to generate default SerialVersionUID's. To generate default SerialVersionUID's JVM will use internally some complex algorithm which may create a performance problem.

Example of SerialVersionUID:

We can solve the above problems by configuring our own SerialVersionUID. We can configure SerialVersionUID as follows.
private static final long serialVersionUID = 1L;

// A class contains two variables which are going to serialize
import java.io.*;

class Example implements Serializable
{


// Our own SerialVersionUID
private static final long serialVersionUID = 103;
int a = 10;
int b = 20;
}

// sender side program to serialize object import java.io.*;
class Sender
{
Example obj1 = new Example();
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject();
}

// Receiver side program to deserialize object import java.io.*;
class Reciever
{
Example obj1 = new Example();
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Example obj2 = (Example)ois.readObject();
System.out.println("The value of a is: ", +obj2.a);
System.out.println("The value of b is: ", +obj2.b);
}

Output:
The value of a is: 10
The value of b is:  20

You may also like:


What are Java Beans?
What is a polymorphism in Java? 
Constructor in Java
MVC Architecture in JSP explained with a login application 
What are JDBC Driver and its types? 
What is JAAS?

No comments:

Post a Comment