Singleton can be broken by using Reflection and the below code demonstrates the same.

Singleton Class

package com.test.singleton;

public class Singleton {

	private static Singleton singleton  = null;

	private Singleton() {
		System.out.println("Running Constructor......");
	}

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

}

Test Class

package com.test.singleton;

import java.lang.reflect.Constructor;
public class SingletonBroken {

	public static void main(String[] args) throws Exception  {
		Singleton instance1 = Singleton.getInstance();
		Class singletonClass = Singleton.class;

		Constructor constructor = singletonClass.getDeclaredConstructor();
		constructor.setAccessible(true);

		Singleton instance2 = (Singleton) constructor.newInstance();
	}

}

Output :

Running Constructor……
Running Constructor……

Now we know that our Singleton Class is no more a Singleton :( . One may need to handle this. This can be avoided by denying the ReflectPermission to the program, but this will fail many API’s (Spring, Hibernate .. ) which requires reflection to work. Another way of avoiding this is to handle ourselves in the constructor so that the constructor throws exception if an instance already exists.

Modified Singleton Class – Throws Exception

package com.test.singleton.exception;

public class Singleton {
private static Singleton singleton  = null;

	private Singleton() throws Exception {
		if(singleton!=null)
			throw new IllegalAccessException("Instance Already Exists !");
		System.out.println("Running Constructor......");
	}

	public static Singleton getInstance() throws Exception{
		if(singleton==null)
			singleton  = new Singleton();
		return singleton;
	}
}

Output :

Running Constructor......
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.test.singleton.exception.SingletonTest.main(SingletonTest.java:16)
Caused by: java.lang.IllegalAccessException: Instance Already Exists !
	at com.test.singleton.exception.Singleton.(Singleton.java:8)
	... 5 more

Now our application throws error if the constructor is invoked more than once.
Objenesis will even bypass the constructor code. so all the above things will not work.

« »