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.