Why Enum Singletons Are Safer Than Class Singletons

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:

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:

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:

    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!

    Create your own website, free on WordPress.com.Create your own website.
    Start free