2017  Kodetalk | Feedback | Privacy Policy | Terms | About
userimage

Java Serialization of a Singleton object

First let"s see what is a singleton object?

Basically in Java we can create objects by calling constructor and if we want to control object instantiation and there could be many reasons why we want to control the object creation at run time. Normally in MVC architecture we create single instance of service and DAO objects since we don"t want to create multiple DAO objects as number of database connections are limited and by creating multiple DAO objects we don"t want to exhaust database connections.

Code snippet for a singleton class

package com.sandipram.connection;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * Here we are making DatabaseConnectionFactory as a singleton. Since we want connection
 * factory to be initiated once and used by different classes of the project. We
 * also want to read the connection parameters once and use it as a place holder
 * for pooled connections.
 *
 * @author SandipRam
 *
 */
public class DatabaseConnectionFactory implements Serializable {

    // Static variable for holding singleton reference object
    private static DatabaseConnectionFactory INSTANCE;

    private DatabaseConnectionFactory() {

    }

    /**
     * Static method for fetching the instance
     *
     * @return
     */
    public static DatabaseConnectionFactory getInstance() {
        // Check whether instance is null or not
        if (INSTANCE == null) {
            // Locking the class object
            synchronized (DatabaseConnectionFactory.class) {
                // Doing double check for the instance
                // This is required in case first time two threads
                // simultaneously invoke
                // getInstance(). So when another thread get the lock,it should
                // not create the
                // object again as its already created by the previous thread.
                if (INSTANCE == null)
                    INSTANCE = new DatabaseConnectionFactory();
            }
        }
        return INSTANCE;
    }

    /* private Object readResolve() throws ObjectStreamException {
        return INSTANCE;
    } */
}


What will happens when we serialize the singleton class?

Serialization allows storing the object in some data store and re create it later on based on requirement. However when we serialize a singleton class and invoke deserialization multiple times. We can end up with multiple objects of the singleton class.Even though constructor is private, deserialization process gets hold of the private constructor while recreating the object from the serialized data store. Will go through step by step and explain that needs to be done when we reconstruct the object from the serialized data store so that singleton behavior is not broken when object reconstruction happens.

Case-1: Serialization breaking singleton behavior


Here we are serializing the singleton instance and reading it multiple times. So we will see that INSTANCE reference is same, however multiple objects are created.

package com.sandipram.connection;

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

/**
 *
 * @author SandipRam
 *
 */
public class SerializationSingletonObject {
    /**
     * @param args
     * @throws IOException
     * @throws FileNotFoundException
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        DatabaseConnectionFactory INSTANCE = DatabaseConnectionFactory.getInstance();

        // Here I am serializing the connection factory instance
        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("dbConnFactory.ser"));
        oos.writeObject(INSTANCE);
        oos.close();

        // Here I am recreating the instance by reading the serialized object
        // data store
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dbConnFactory.ser"));
        DatabaseConnectionFactory factory1 = (DatabaseConnectionFactory) ois.readObject();
        ois.close();

        // I am recreating the instance AGAIN by reading the serialized object
        // data store
        ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream("dbConnFactory.ser"));
        DatabaseConnectionFactory factory2 = (DatabaseConnectionFactory) ois2.readObject();
        ois2.close();

        // Lets see how we have broken the singleton behavior

        System.out.println("Instance reference check1 -->" + factory1.getInstance());
        System.out.println("Instance reference check2 -->" + factory2.getInstance());
        System.out.println("=========================================================");
        System.out.println("Object reference check1 -->" + factory1);
        System.out.println("Object reference check2 -->" + factory2);
    }
}


Output is as follows:-

Instance reference check1 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e
Instance reference check2 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e
=========================================================
Object reference check1 -->com.sandipram.connection.DatabaseConnectionFactory@5c647e05
Object reference check2 -->com.sandipram.connection.DatabaseConnectionFactory@33909752



So it has created two objects and one static reference for INSTANCE. So that means if we read the serialized format of singleton object multiple times, we will create multiple objects. This is not what singleton object is supposed to do. Now,

Case-2: Serialization and singleton working properly

In order to make serialization and singleton work properly, we have to introduce readResolve() method in the singleton class.readResolve() method lets developer control what object should be returned  on deserialization.
For the current DatabaseConnectionFactory singleton class, readResolve() method will look like this.

/**
* Special hook provided by serialization where developer can control what object needs to sent.
* However this method is invoked on the new object instance created by deserialization process.
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return INSTANCE;
}



Output  is as follows:-

Instance reference check1 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e
Instance reference check2 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e
=========================================================
Object reference check1 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e
Object reference check2 -->com.sandipram.connection.DatabaseConnectionFactory@70dea4e


So now serialization and singleton is working properly and it does not matter how many times we read the serialized format of singleton object. We will get the one instance.readResolve().