DEV Community

Thellu
Thellu

Posted on

How to Prevent Serialization from Breaking the Singleton Pattern in Java

Singleton is a commonly used design pattern that ensures a class has only one instance and provides a global point of access to it.

However, serialization can silently break the Singleton guarantee by creating a new instance during deserialization. In this article, we'll explore why that happens and how to fix it.


The Problem: Serialization Breaks Singleton

Let's start with a basic Singleton class:

import java.io.*; class Singleton implements Serializable { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } 
Enter fullscreen mode Exit fullscreen mode

Now let's serialize and deserialize the singleton:

Singleton instance1 = Singleton.getInstance(); // Serialize to a file ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser")); out.writeObject(instance1); out.close(); // Deserialize from the file ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser")); Singleton instance2 = (Singleton) in.readObject(); in.close(); System.out.println(instance1 == instance2); // false ❌ 
Enter fullscreen mode Exit fullscreen mode

Even though the Singleton was correctly implemented, deserialization created a new object, violating the Singleton property.


The Fix: Implement readResolve()

Java provides a hook called readResolve() that lets you control what object is returned during deserialization.

Fix the Singleton class like this:

class Singleton implements Serializable { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } // This ensures that deserialization returns the original instance private Object readResolve() throws ObjectStreamException { return instance; } } 
Enter fullscreen mode Exit fullscreen mode

Now serialization and deserialization will preserve the singleton instance:

System.out.println(instance1 == instance2); // true ✅ 
Enter fullscreen mode Exit fullscreen mode

Notes

  • The readResolve() method must be private and return Object.
  • Without it, Java's serialization mechanism creates a new instance.
  • Always test singleton classes that implement Serializable.

Bonus: Prevent Reflection-Based Attacks (Optional)

Serialization isn't the only threat to Singleton. Reflection can also break it.

You can throw an exception in the constructor if an instance already exists:

private Singleton() { if (instance != null) { throw new RuntimeException("Use getInstance() method to get the single instance of this class"); } } 
Enter fullscreen mode Exit fullscreen mode

Conclusion

Serialization can undermine Singleton, but readResolve() is a simple yet powerful tool to maintain the Singleton contract.

Always be cautious when marking a Singleton class as Serializable, especially in distributed systems, caching, or when passing objects over the network.

Top comments (0)