Saturday 27 May 2017

Serialization/DeSerialization

Serialization: Serialization in Java is a process of converting Java object into byte stream in order to transfer it over the network or write it into file or database.


Deserialization: Deserialization in java is a process of converting byte stream back into Java object.

1. Why serialization: Very first question interviewer may ask you that why we need serialization in java?
Answer: As we already know we either store java object (in File System or Database) in order to persist the state or transfer it over the network to do remote(EJB etc.) call. There are two important facts first we can't write Java objects directly into File or DB as they can only understand byte streams. In order to do so we need to convert our Java object into byte streams so we can write it into File or in DB. Second we know that we can't transfer Java objects directly over the network(as all network protocol only supports byte streams.)
Serialization is required to make Java application capable of transfer Java object over the network or store it into File or DB in form of stream of bytes. 

Below figure illustrates serialization process.

Serialization process

2. How to perform Serialization: Next question interviewer may ask you to write code for serialization in Java.
AnswerTo answer this question you need to aware about classes/interfaces that are required and which are as follows:


1. Serializable interface : It is a marker interface provided by java under java.io package.


2. ObjectOutputStream and ObjcetInputStream : This is helper class for serialization under java.io package.


After you know classes/interfaces require for serialization let's follow below mentioned steps (Full code is provided below).


Step 1: Implements serializable interface in class which you want to serialize, See below code at Line number 43 where Employee class implements Serializable interface to support serialization.


Step 2: Create object of your class and we will serialize this object, See below code from line number 12-14 where we are creating new object of Employee with values of empId and empName.


Step 3: Create object of ObjectOutputStream class and call writeObject method which will take object as input and will return byte stream which we can write to any output stream(in below code we are using FileOutputStream to write bytes in a file called employee.ser), See below code from Line number 28-37.

Note: .ser is not a mandatory extension for files. We can have any extension like .txt etc, It's just a standard practice.
Step 4: We have byte stream, which we can write into file or transfer over the network. Below is working example of serialization:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class TestSerialization {

 public static void main(String[] args) {
  Employee emp = new Employee();
  emp.setEmpId(11);
  emp.setEmpName("John");
  
  /****Serialization : Start*****/
  System.out.println("Object created empId::::"+emp.getEmpId()+" empName:::"+emp.getEmpName());
  try {
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("employee.ser")));
   objectOutputStream.writeObject(emp);
  } catch (IOException e) {
   e.printStackTrace();
  }
  /****Serialization : End*****/
  
  
  /***Deserialization : Start*****/
  try {
   ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("employee.ser")));
   Employee emp1 =  (Employee)objectInputStream.readObject();
   System.out.println("After Deserializatione empId::::"+emp1.getEmpId()+" empName:::"+emp1.getEmpName());
  }catch (IOException e) {
   e.printStackTrace();
  }
  catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  /*****Deserialization : End*****/ 
 }
}

class Employee implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = -3416071904967554721L;
 
 Integer empId;
 String empName;

 public Integer getEmpId() {
  return empId;
 }
 public void setEmpId(Integer empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
}

3. What is serialVersionUID: Next important question interviewer may ask you that is about serialVersionUID?
AnswerserialVersionUID is a static and final member variable which indicates version of your class, see at line number 47 in above code where we have generated serialVersionUID.

There are two way to generate serialVersionUID for your class:

1.Default 
2.Generated

Followup question: Why there is need for serialVersionUID?,
Answer: Whenever you serialize your object, Java compiler does attach current serialVersionUID with the serialized bytes as well, Later on whenever you deserialize bytes stream to get back original Java object at that time java compiler compares serialVersionUID that you have in your class with serialVersionUID of serialized bytes in order to make sure class has not modified in between. 
So we can say that serialVersionUID helps Java to check consistency of object with current structure of class.

4.What is transient variable: Next but very important interview question as well as very useful concept.
AnswerWhenever you ask Java to serialize your object, As per default behavior Java serializes all member variables' state (value of that variable) for a given object. But there are some scenarios when you don't want to serialize one or more member(s) variables' state. In order to tell Java about those variables(not to consider for serialization) you need to mark those variables as transient in your class.

Followup question 1What will be the value of transient variable after deserialization?

Answer: Since Java ignores state(value) of transient variables while serialization hence when we perform deserialization Java assigns those variables default value.
So we can say that transient is a hint to Java to ignore all variables' state which are mark as transient while serializing object into bytes and take their default value while deserialization.
Followup question 2Which are variables (properties) of our class we should mark as transient or How we can decide which variable(s) need to mark as transient for a given class?
Answer: Since Java ignores value of transient variables while serialization and gives us default value after deserialization.
It's clear from above fact that we should consider those variables whose value we derived(depends on other properties).
For example If there is variable which stores time-stamp of object creation. In that case if we don't mark it as transient we will get same(first time when we have created) time-stamp whenever you perform deserialization. But as we know deserialization it self creates a new object so we want current time stamp (when you deserialize it, not when you crated object first time).
So we can say that we use transient variables when we want some default value(as per business logic) whenever we create object.
Note: Please note that deserialization crates a new object same as we create using "new" keyword.


5.Can we serialize static member variables: Next important question to check your knowledge of static variables in perspective of serialization.
Answer: As we know so far that we can only serialize objects in Java and we also know the fact that static variables belongs to class and not to object. It means all object share same static value, Hence whenever we serialize a object with static fields, Java ignores static fields and after deserialization it gives you default value for all static member variables.

Hence we can say that static fields do not take part in serialization and always gives you default value after deserialization.

Note: If you run below code snippet in your local machine you will find that after deserialization static member variable "empName" displaying the same value (at line number 31) what you have assigned earlier(at line number 14) instead of default value as I said above. The reason is we are running the code in same JVM that's why the object we got after deserialization will share same static value.

In actual practice serialization and deserialization happens in two different machine(hence two different JVM).


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class StaticSerializationTest {

 public static void main(String[] args) {
  Employee emp = new Employee();
  emp.setEmpId(11);
  Employee.empName = "John"; // assigning static value to empName.
  
  /****Serialization : Start*****/
  System.out.println("Object created empId::::"+emp.getEmpId()+" empName:::"+emp.getEmpName()); // It will print "Object created empId::::11 empName:::John"
  try {
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("employee.ser")));
   objectOutputStream.writeObject(emp);
  } catch (IOException e) {
   e.printStackTrace();
  }
  /****Serialization : End*****/
  
  
  /***Deserialization : Start*****/
  try {
   ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("employee.ser")));
   Employee emp1 =  (Employee)objectInputStream.readObject();
   System.out.println("After Deserialization empId::::"+emp1.getEmpId()+" empName:::"+emp1.getEmpName()); // It will print "After Deserialization empId::::11 empName:::John"
  }catch (IOException e) {
   e.printStackTrace();
  }
  catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  /*****Deserialization : End*****/ 
 }
}

class Employee implements Serializable{
 /**
  * 
  */
 private static final long serialVersionUID = -3416071904967554721L;
 
 Integer empId;
 static String empName;

 public Integer getEmpId() {
  return empId;
 }
 public void setEmpId(Integer empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
}


6. Serialization with member variable of Custom type: Under this interviewer may ask you that what will happen if a class contains member variable of custom type and that type doesn't implements Serializable interface?
Answer: While serializing an object Java first checks whether all member variable supports serialization or not i.e. whether or not they have implemented the Serializable interface, if any one of member variable doesn't support serialization Java throws run time exception(NotSerializableException).

Note: If you check code of in-built Java classes like String, Number etc. you will find that they all implement Serializable interface in order to support serialization.

In below code you have a member variable wheel of type Wheel which doesn't implement Serializable interface hence doesn't support serialization. When we try to serialize car object Java throws run time exception because wheel object( which is part of car object) doesn't supports serialization, See at line number 16.

So if you remove reference of Wheel from Car class Java won't throw any exception and car object will serialize fine.

Also if we want to serialize wheel object along with car object instead of removing it form Car class we need to implement Serializable for Wheel class as well then Java will not throw any exception.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializationExceptionTest {

 public static void main(String[] args) {
  Car car = new Car();
  car.setWheel(new Wheel());
  
  /****Serialization : Start*****/
  try {
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("employee.ser")));
   objectOutputStream.writeObject(car); //It will throw java.io.NotSerializableException: Wheel
  } catch (IOException e) {
   e.printStackTrace();
  }
  /****Serialization : End*****/
 }
}

class Car implements Serializable{
 private static final long serialVersionUID = -8948008914233045493L;
 private Wheel wheel;
 
 public Wheel getWheel() {
  return wheel;
 }
 public void setWheel(Wheel wheel) {
  this.wheel = wheel;
 }
}

class Wheel{
 
}

7. Serialization and Inheritance: First question Interviewer may ask you that what will happen if parents class implements Serializable interface but child class doesn't?
Answer: Whenever we ask to serialize any object Java serialize whole class hierarchy(all child classes) hence even if child class doesn't implement Serializable interface it will be part of Serialization.

But if we want mentioned 
explicitly that child class should not support serialization than you need to override two method redaObject() and writeObject() and need to throw java.io.NotSerializableException exception.

Followup question 1What if a child class implement Serializable interface but parents doesn't?
Answer: If your child class implements Serializable but parents class doesn't in this case parent class should provide default constructor in order to serialize child class object. 

No comments:

Post a Comment