Tuesday 28 June 2016

Serialization Vs Singleton

In my previous post, I explained what is singleton design pattern is, how to restrict a class to construct only one object. I request you to go through the post, if you don't know about singleton design pattern. In this post I am going to explain how serialization breaks the singleton design pattern.

What is Serialization?
Serialization is the process of converting object state into sequence of bytes so that it can be persisted in memory, we can transfer this persisted state of object across network.

What is deserialization?
Deserialization is the process of converting the bytes of data to an object.


Let me show you simple example of singleton class.
class SingleTon {
 static SingleTon instance = null;

 private SingleTon() {

 }

 public static SingleTon getInstance() {
  if (instance == null) {
   synchronized (SingleTon.class) {
    if (instance == null) {
     instance = new SingleTon();
    }
   }
  }
  return instance;
 }

}

public class TestSingleton {
 public static void main(String args[]) {
  SingleTon obj1 = SingleTon.getInstance();
  SingleTon obj2 = SingleTon.getInstance();
  SingleTon obj3 = SingleTon.getInstance();

  System.out.println(obj1);
  System.out.println(obj2);
  System.out.println(obj3);
 }
}


Output
SingleTon@7852e922
SingleTon@7852e922
SingleTon@7852e922

As you observe the output, you are always getting same reference.


Now let me add serialization functionality to the class SingleTon.
import java.io.Serializable;

class SingleTon implements Serializable {
 private static final long serialVersionUID = 1L;

 static SingleTon instance = null;

 private SingleTon() {

 }

 public static SingleTon getInstance() {
  if (instance == null) {
   synchronized (SingleTon.class) {
    if (instance == null) {
     instance = new SingleTon();
    }
   }
  }
  return instance;
 }

}


Now update TestSingleton class like below.
a.   get the singleton object
b.   Serialize the object to a file.
c.    Deserialize the object and check whether you are getting same or not.

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

public class TestSingleton {
 private static ObjectInputStream in;
 private static ObjectOutputStream out;

 public static void main(String args[]) throws Exception {

  /* Serialize object */
  FileOutputStream fos = new FileOutputStream("ser.out");
  out = new ObjectOutputStream(fos);
  SingleTon obj1 = SingleTon.getInstance();
  out.writeObject(obj1);

  /* Deserialize object */
  FileInputStream fis = new FileInputStream("ser.out");
  in = new ObjectInputStream(fis);
  SingleTon obj2 = (SingleTon) in.readObject();

  /* Deserialize object */
  fis = new FileInputStream("ser.out");
  in = new ObjectInputStream(fis);
  SingleTon obj3 = (SingleTon) in.readObject();

  System.out.println(obj1);
  System.out.println(obj2);
  System.out.println(obj3);
 }
}


Output

SingleTon@3d4eac69
SingleTon@1b28cdfa
SingleTon@eed1f14


As you see the output, I can able to create more than one object for singleton class.

How to get rid of this behavior?
To make singleton pattern works properly, Singleton class must implement the method readResolve. By using readResolve method, you can control what object should be returned on deserialization. Update Singleton class like below.
import java.io.Serializable;

class SingleTon implements Serializable {
 private static final long serialVersionUID = 1L;

 static SingleTon instance = null;

 private SingleTon() {

 }

 public static SingleTon getInstance() {
  if (instance == null) {
   synchronized (SingleTon.class) {
    if (instance == null) {
     instance = new SingleTon();
    }
   }
  }
  return instance;
 }

 private Object readResolve()   {
  return instance;
 }

}


Re run TestSingleton class. You will get following kind of output.

No comments:

Post a Comment