How to break Singleton class in java

Overall notion of Singleton class lies in getting one and only one instance of the class. Much of our functionality relies on the base that there will be only one object of a class we intentionally designed to be Singleton. What if the same class produces more than one object in some scenario? Woaaah!!! Our code blows away.

For all those who are anxious to know how this could be done to break a Singleton class or how to write Singleton class so that it is not broken, there is some interesting stuff below:

1. Break by Cloning

If a Singleton class implements java.lang.Cloneable interface then invoking clone() method on its single instance creates a duplicate object. Consider the below code:

public class MyClass implements Cloneable{

	private static MyClass instance = new MyClass();

	private static MyClass getInstance(){
		return instance;
	}

	public static void main(String[] args) 
                      throws CloneNotSupportedException {
		MyClass obj = MyClass.getInstance();
		System.out.println(obj);
		System.out.println(obj.clone());
	}	
}

This prints

com.MyClass@544a5ab2
com.MyClass@5d888759

See!!! Two distinct objects. Singleton gone away.

Remedy
Don’t make the class which should be Singleton implement java.lang.Cloneable. If it extends a class which implements Cloneable, then override clone method and throw CloneNotSupportedException from it. This will prevent clone creation.


2. Deserialization also breaks Singleton
Deserialization means bringing a saved object back to life. When a class is deserialized, a fresh instance of the class is created and its instance variables are then set to the values which were serialized.
What does a fresh instance creation means if the serialized class was Singleton? Simple, More than one object. See below

	MyClass ob= MyClass.getInstance();
	System.out.println(ob);

	// ..code to serialize object goes here
	
        // ..code to deserialize saved object here

	MyClass newObject = (MyClass)inputStream.readObject(); 
	//inputStream is the stream connected to the medium to which the object 
        //was serialized, e.g., a file  
	System.out.println(newObject);
	//re-initialize the same input stream or 
	//use another inputstream to read the object once again
	MyClass anotherObject = (MyClass)inputStreamNew.readObject();
	System.out.println(anotherObject);

The output is

com.MyClass@2da679b7
com.MyClass@6bbc4459

Again, distinct objects.

Remedy
Override readResolve method and return the same Singleton instance every time. readResolve method is called after the object has been read from the stream but before it is returned to the calling code. For implementing this method just put the following code into your Serializable class:

private Object readResolve(){
		return instance;
}

3. Reflection can instantiate a Singleton multiple times
Using java reflection api, we can tweak into a class by getting details like its fields, constructor, invoking its methods etc. Reflection can also be used to create new instance of a class. Obviously, if the class is Singleton, then creating a new instance again breaks its Singleton nature. See below

try {
	//load class
	Class c = Class.forName("com.codippa.MyClass");
	//get all constructors (whether public or private)
	Constructor[] constructors = c.getDeclaredConstructors();
	//suppress access check errors
	constructors[0].setAccessible(true);
	//instance no 1
	System.out.println(constructors[0].newInstance());
	//instance no 2
	System.out.println(constructors[0].newInstance());
} catch (ClassNotFoundException e) {
		e.printStackTrace();
} catch (InstantiationException e) {
		e.printStackTrace();
} catch (IllegalAccessException e) {
		e.printStackTrace();
} catch (IllegalArgumentException e) {
		e.printStackTrace();
} catch (InvocationTargetException e) {
		e.printStackTrace();
}

The above code prints

com.MyClass@5d888759
com. MyClass@2e6e1408

Clearly the two objects are different.

Remedy
Check the static instance to be not null and throw Error if it is not null which means one instance already exists as.

 
private MyClass () {
	if(inst!=null){
		throw new InstantiationError("Already there");
	}
}

Hope the above post let you understand the ways to break a Singleton. Keep the above points in mind when designing a Singleton.
Hit the clap below to show your appreciation if you liked the article.

1 Comment

Leave a Reply