I was doing research on singleton and I have developed a very basic singleton class..
public class SingletonObject {
private static SingletonObject ref;
private SingletonObject () //private constructor
{ }
public static synchronized SingletonObject getSingletonObject()
{
if (ref == null)
ref = new SingletonObject();
return ref;
}
public Object clone() throws CloneNotSupportedException
{throw new CloneNotSupportedException ();
}
}
Now below is the one way which I have cracked the singleton..
public class CrackingSingleton {
public static void main(String[] args) throws ClassNotFoundException,
IllegalArgumentException, SecurityException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
//First statement retrieves the Constructor object for private constructor of SimpleSingleton class.
Constructor pvtConstructor = Class.forName("CrackingSingleton.SingletonObject").getDeclaredConstructors()[0];
//Since the constructor retrieved is a private one, we need to set its accessibility to true.
pvtConstructor.setAccessible(true);
//Last statement invokes the private constructor and create a new instance of SimpleSingleton class.
SingletonObject notSingleton1 = ( SingletonObject) pvtConstructor.newInstance(null);
System.out.println(notSingleton1.hashCode());
System.out.println("notSingleton1 --->"+notSingleton1.toString());
SingletonObject notSingleton2 = ( SingletonObject) pvtConstructor.newInstance(null);
System.out.println("notSingleton2 --->"+notSingleton2.hashCode());
System.out.println(notSingleton2.toString());
}
}
Please advise other ways also by which the singleton can be cracked..!!
Three ways I can think of are:
Serialization
If your singleton class is serializable, then you could serialize an instance of it, and deserialize it back and get a second object of that class.
You could avoid this by implementing readResolve method.
Class Loading
The same class could be loaded by two different class loaders, as such, you could create two instances of your singleton class by simply invoking its
getInstancemethod in a class loaded by two different class loaders. This approach would work without having to resort to violating the private constructor.Reflection
As you have well pointed out, via reflection you could create two instances of the class. I think the previous examples was just a variant of the same approach. But I believe you could prevent these two from happening using a
SecurityManager.