Serialization and Singleton Design Pattern
This is our forth article in the series of Singleton Design Pattern Articles. The purpose of the singleton class is to control object creation, limiting the number of objects to only one.
In our previous three articles, we have discussed how we can create Singleton Design Pattern in Single-threaded and multithreaded environment. We have also discussed how we can prevent object cloning if our Singleton class is Cloneable.
In this article, we will discuss how we can prevent creating more than one instance in case our Singleton class has implemented Serializable interface.
For navigating to the other articles on Singleton Design Pattern, please refer table of contents.
Serializable Singleton
Sometimes in distributed systems, we are required to store state of java objects in file system and retrieve it later point of time. To achieve this, Java provides built in Serialization mechanism. Basic requirement to mark our class as Serializable is to implement Serializable marker interface.
Let's make our Singleton class Serializable. For Simplicity I am using Eager Initialization Approach for the demo.
import java.io.Serializable; public class SerializableSingleton implements Serializable{ private static SerializableSingleton instance = new SerializableSingleton(); private SerializableSingleton() { System.out.println("Constructor is being called"); } public static SerializableSingleton getInstance() { return instance; } }
Let’s test our singleton class whether it maintains single instance after serializable and deserializable operations?
public static void main(String args[]) { try { SerializableSingleton instance1 = SerializableSingleton.getInstance(); ObjectOutput out = null; // Serialize object state to file out = new ObjectOutputStream(new FileOutputStream("codePumpkin.ser")); out.writeObject(instance1); out.close(); // deserialize from file to object ObjectInput in = new ObjectInputStream(new FileInputStream("codePumpkin.ser")); SerializableSingleton instance2 = (SerializableSingleton) in.readObject(); in.close(); System.out.println("instance1 hashCode = " + instance1.hashCode()); System.out.println("instance2 hashCode = " + instance2.hashCode()); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }
Output
instance1 hashCode = 118352462 instance2 hashCode = 1406718218
readResolve() method
We can see that the hash code of both the instances are different in above example. That clearly violates singleton principle. The problem with above serialized singleton class is that whenever we deserialize it, it will create a new instance of the class. We can prevent this by providing implementation readResolve()
method as shown below.
protected Object readResolve() { return getInstance(); }
During serialization process readObject()
is used to create instance and it creates new instance every time we deserialize the Singleton object. But we can replace that newly created instance in the stream with our original Singleton instance using readResolve()
. No reference to the newly created instance is retained, so it immediately becomes eligible for garbage collection.
transient fields
If we are depending on readResolve()
method, we must declare all instance fields with object reference types as transient. Otherwise, it is possible for a determined attacker to secure a reference to the deserialized object before its readResolve()
method is run.
You can read more about How attacker can break the singleton pattern if fields are not transient in chapter 77 of Joshua Bloch's Effective Java 2nd Edition. Here is the summary of that chapter :
The attack is a bit complicated, but the underlying idea is simple. If a singleton contains a non-transient object reference field, the contents of this field will be deserialized before the singleton’s
readResolve()
method is run. This allows a carefully crafted stream to “steal” a reference to the originally deserialized singleton at the time the contents of the object reference field are deserialized.
Additional Serialization Care
Along with readResolve()
method implementation, we should also declare serialVersionUID
in our Singleton class. This is just a good practice and not mandatory for achieving Serializable Singleton.
Here is the complete Java Program code for Serializable Singleton:
import java.io.*; public class SerializableSingleton implements Serializable { private static final long serialVersionUID = 1L; private static SerializableSingleton instance = new SerializableSingleton(); // make additional fields transient transient String[] xyz = {"xyz1", "xyz2", "xyz3"}; private SerializableSingleton() { } public static SerializableSingleton getInstance() { return instance; } protected Object readResolve() { return getInstance(); } }
Download Complete Java Program »
If Singleton class has not implemented Serialiable
interface, then Java will give NotSerializableException
when some attacker will try to serialize Singleton object. In other words, if we have not implemented Serializable
interface, we do not require to worry about all these attacks at all.
Then, Why do we need to make our Singleton class Serializable?
Well it is not at all required. There is no useful real world scenario where we require to Serialize Singleton Object. A singleton usually doesn't change of state throughout its lifetime nor contains any state which we can save/restore. If it does, then it is already wrong to make it a singleton.
Java SE API contains two Singleton implementations
None of them implements serializable
. It also doesn't make any sense as well.
However, here is one case where we may require to handle Serialization while implementing Singleton Design Pattern.
What if super class has implemented Serialization interface?
If our Singleton class is required to inherit all the properties of some class i.e. ParentClass
and that class is Serializable
. For Example,
class ParentClass implements Serializable{ } public class SerializableSingleton extends ParentClass { // Singleton Code }
Well in this case, we need to take all the preventive actions like make all the fields transient
and provide readResolve()
method implementation.
There is also one more approach to handle this scenario. Override writeObject()
method and throw
NotSerializableException
from it. It will behave same as you have not implemented Serializable
interface.
Next Article in the series of Singleton Design Pattern : Breaking Singleton using reflection and Enum Singleton
That's all for this topic. If you guys have any suggestions or queries, feel free to drop a comment. We would be happy to add that in our post. You can also contribute your articles by creating contributor account here.
Happy Learning 🙂
If you like the content on CodePumpkin and if you wish to do something for the community and the planet Earth, you can donate to our campaign for planting more trees at CodePumpkin Cauvery Calling Campaign.
We may not get time to plant a tree, but we can definitely donate ₹42 per Tree.
About the Author
Tags: Core Java, Creational Design Patterns, Design Patterns, Java, serialization, Singleton, Singleton Design Pattern, transient
Comments and Queries
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:<pre><code class="java"> String foo = "bar"; </code></pre>For more information on supported HTML tags in disqus comment, click here.