Class Based Singleton vs Enum Singleton | Security
I’ll discuss two ways of creating a singleton and explain why one is better than the other.
Let’s start with Class Based Singleton. We will create a singleton that should be thread safe by using the keyword synchronized and our singleton instance will be volatile.
Why volatile? The answer is “Double-Checked Locking”!
We want to ensure all threads see the most up-to-date value of the instance from main memory. Without doing so we could have threads seeing an instance is not quite null but also partially initialized.
The code for a class based singleton:
public class ClassBasedSingleton { private static volatile ClassBasedSingleton plainSingleton; private ClassBasedSingleton(){ } public static ClassBasedSingleton getPlainSingleton(){ if(plainSingleton == null){ synchronized (ClassBasedSingleton.class) { if(plainSingleton == null){ return new ClassBasedSingleton(); } } } return plainSingleton; }}
Ok, we achieved our goal. What’s the problem?
The problem is this code is not secure. We want to prevent Reflection Based Instantiation.
Let’s get an instance via reflection using ReflectionBasedInstantiationForClassBasedSingletonTest:
ublic class ReflectionBasedInstantiationForClassBasedSingletonTest { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { // 1. Get the Class object for the target class Class<?> clazz = ClassBasedSingleton.class; // 2. Get the declared constructor (even if it's private) Constructor<?> constructor = clazz.getDeclaredConstructor(); // 3. Make the constructor accessible constructor.setAccessible(true); // 4. Instantiate the object ClassBasedSingleton instance = (ClassBasedSingleton) constructor.newInstance(); System.out.println("Instance created: " + instance); }}
Output from this code, using the ClassBasedSingleton:
Instance created: singleton.ClassBasedSingleton@f6f4d33
As you can see, we have no errors attempting to access this singleton. Probably not what we want!
Let’s compare this to using an Enum singleton.
Enum singleton code:
public enum EnumSingleton { SINGLETON; private int counter = 123; public synchronized void increment(){ counter++; } public int getCounter(){ return counter; }}
When we run this through our ReflectionBasedInstantiationForEnumBasedSingletonTest:
public class ReflectionBasedInstantiationForEnumBasedSingletonTest { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { // 1. Get the Class object for the target class Class<?> clazz = EnumSingleton.class; // 2. Get the declared constructor (even if it's private) Constructor<?> constructor = clazz.getDeclaredConstructor(); // 3. Make the constructor accessible constructor.setAccessible(true); // 4. Instantiate the object EnumSingleton instance = (EnumSingleton) constructor.newInstance(); System.out.println("Instance created: " + instance); }}
this is what we get:
Exception in thread “main” java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.base/java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:544)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:496)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483)
at singleton.ReflectionBasedInstantiationTest.main(ReflectionBasedInstantiationTest.java:22)
We cannot access the singleton instance using reflection.
Safe!
So what’s happening here?
Java prevents reflection from creating the enum using reflection.
We can take this a step further and show how Java prevents a 2nd instance creation:
public class TestEnumSingletonGetSecondInstance { public static void main(String[] args){ EnumSingleton instance1 = EnumSingleton.SINGLETON; int counter = instance1.getCounter(); System.out.println("counter from EnumSingleton: "+counter); try { // 1. Get the constructor for the enum // Note: Enum constructors take (String name, int ordinal) Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class); // 2. Try to bypass the 'private' modifier constructor.setAccessible(true); // 3. Try to create a NEW instance (This is where it fails!) EnumSingleton instance2 = constructor.newInstance("ATTACK_INSTANCE", 1); int counter2 = instance2.getCounter(); System.out.println("counter2 from EnumSingleton: "+counter2); } catch (Exception e) { System.err.println("\n--- REFLECTION ATTACK FAILED ---"); System.err.println("Exception: " + e.getClass().getSimpleName()); System.err.println("Message: " + e.getMessage()); } }}
And we get this printout on the console:
counter from EnumSingleton: 123
— REFLECTION ATTACK FAILED —
Exception: IllegalArgumentException
Message: Cannot reflectively create enum objects
We get the exception caught in the catch and we do not see the printout from the 2nd enum instance because of the exception.
Cheers!



