How To Save Singleton Pattern from Reflection Serialization and Cloning

Posted By : Navin Purohit | 26-Apr-2018

How to save Singleton pattern from Reflection, Serialization and Cloning?

In Java, singleton pattern is used to avoid creation of multiple instances of a single class. After first-time object creation, if we try to do that, all will point to the same instance. In this blog, we focus not on how to create singleton class rather than we focus on those concepts by which this singleton pattern can be the break and their prevention techniques. So let's start one by one.


1. Reflection: In Java, Reflection API is used to explore or change the behavior of methods, interfaces, classes at runtime.


Let's see how reflection can break the singleton pattern:-

import java.lang.reflect.Constructor;
 
//Singleton class
class Singleton 
{
    public static Singleton singleton;
     
    private Singleton() 
    {
	
    }

    public static Singleton getInstance(){
		If(singleton == null){
			singleton = new  Singleton();
		}
	return singleton;	
    }
}
 
public class ReflectionDemo 
{
 
    public static void main(String[] args)
    {
        Singleton object1 = Singleton.singleton;
        Singleton object2 = null;
        try
        {
            Constructor[] constructors = Singleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) 
            {
                // Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                object2 = (Singleton) constructor.newInstance();
                break;
            }
        }catch (Exception e) 
        {
            e.printStackTrace();
        }
         
    System.out.println("object1 .hashCode():- " + object1.hashCode());
    System.out.println("object2.hashCode():- " + object2.hashCode());
    }
}

 

Output:

object1.hashCode():- 636712542
object2.hashCode():- 122163700


Explanation:-

As you can see that 2 different hashcodes are created for singleton class. Hence singleton pattern has been destroyed using Reflection.


Solution 1:

To overcome above issue we can throw a runtime exception in private constructor if singleton class is already initialized.

Check below piece of code, inside Singleton class:-

class Singleton 
{
    public static Singleton singleton;
     
    private Singleton() 
    {
			if(singleton != null){
				throw new RuntimeException("Do not try to break the Singleton class");
			}
    }

    public static Singleton getInstance(){
		If(singleton == null){
			singleton = new  Singleton();
		}
	return singleton;	
    }
}

 

Solution 2:


To overcome above issue we can use enum also, as java internally instantiated enum value only once. The main drawback of enum is that it doesn’t support lazy initialization.

//Java program for Enum type singleton
public enum Singleton 
{
  INSTANCE;
}

 

2. Serialization: In Java, using serialization we convert an object into the byte stream and send it to the network or save in a file. And at the time de-serialize that object it will create a new object. So serialization on Singleton class is not a good idea, as it breaks the singleton property.


Let's see how Serialization can break the singleton pattern:-

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
class Singleton implements Serializable
{
    public static Singleton singleton;
     
    private Singleton() 
    {
	
    }

    public static Singleton getInstance(){
		If(singleton == null){
		    singleton = new  Singleton();
		}
		return singleton;	
    }
}
 
 
public class SingletonRunner 
{
 
    public static void main(String[] args) 
    {
        try
        {
            Singleton object1 = Singleton.singleton;
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
            out.writeObject(object1);
            out.close();
     
            // deserailize from file to object
            ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
             
            Singleton object2 = (Singleton) in.readObject();
            in.close();
     
            System.out.println("object1 hashCode:- " + object1.hashCode());
            System.out.println("object2 hashCode:- " + object2.hashCode());
        } 
         
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
}

 

Output:

object1 hashCode:- 2520089362
object2 hashCode:- 462123831


Explanation:

As you can see that 2 different hashcodes are created for singleton class. Hence singleton pattern has been destroyed using De-serialization.


Solution 1:

To overcome above issue we have to implement readResolve() method in Singleton class. We can either throw runtime exception from readResolve() method or either return instance of Singleton class. We can check how to implement readReolve() method:-

 

class Singleton implements Serializable
{
    public static Singleton singleton;
     
    private Singleton() 
    {
	
    }

    public static Singleton getInstance(){
		If(singleton == null){
		    singleton = new  Singleton();
		}
		return singleton;	
    }
	
    protected Object readResolve()
    {
        return singleton;
    }
}

 

Solution 2:

To overcome above issue we can use enum also, as this guarantees singleton-ness of the object and return the same instance always.

//Java program for Enum type singleton
public enum Singleton 
{
  INSTANCE;
}

 

3. Cloning: In Java, object duplication or copy is created using clone() method by implementing the clonable interface. If we use cloning on singleton class, then it has two instances of the same class which breaks the singleton pattern.


Let's see how Cloning can break the singleton pattern:-

class SuperClass implements Cloneable
{
  int i = 5;
 
  @Override
  protected Object clone() throws CloneNotSupportedException 
  {
    return super.clone();
  }
}
 
// Singleton class
class Singleton extends SuperClass
{
  public static Singleton singleton;
 
  private Singleton() 
  {
  }
  
  public static Singleton getInstance(){
		If(singleton == null){
		    singleton = new  Singleton();
		}
		return singleton;	
    }
}
 
public class SingletonRunner
{
  public static void main(String[] args) throws CloneNotSupportedException 
  {
    Singleton object1 = Singleton.singleton;
    Singleton object2 = (Singleton) object1.clone();
    System.out.println("object1 hashCode:- " + object1.hashCode());
    System.out.println("object2 hashCode:- " + object2.hashCode()); 
  }
}

 

Output:

object1 hashCode:- 1527082362
object2 hashCode:- 462623031

Explanation:

As you can see that 2 different hashcodes are created for singleton class. Hence singleton pattern has been destroyed using Cloning.


Solution:

To overcome above issue we have to override clone() method in Singleton class. We can either throw an exception from clone() method or either return instance of Singleton class. We can check how to implement clone() method:-

// Singleton class
class Singleton extends SuperClass
{
  public static Singleton singleton;
 
  private Singleton() 
  {
  }
  
  public static Singleton getInstance(){
		If(singleton == null){
		    singleton = new  Singleton();
		}
		return singleton;	
    }
	
	
  @Override
  protected Object clone() throws CloneNotSupportedException 
  {
    throw new CloneNotSupportedException();
	//Or we can return instance of singleton class
	/*
		return singleton;
	*/
  }
}

About Author

Author Image
Navin Purohit

Navin has an experience of 4 years in Java and NodeJS. He is eager to learn new technologies and want to explore his inner strengths.

Request for Proposal

Name is required

Comment is required

Sending message..