I am trying to write a Serializable Singleton class by adding the readResolve() method. My intention is to get the same object with its object's state at the time of serialization time.
below is my Test example code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SingletonDemo {
public static void main(String[] args) {
Singleton obj = Singleton.getInstance();
System.out.println("After NEW Object creation : " + obj);
obj.i = 5;
System.out.println("Object modified");
System.out.println("After Object 1st Modification : " + obj);
serializeMe();
System.out.println("Serialized successfully with object state : " + obj);
obj.i = 10;
System.out.println("Object modified again");
System.out.println("After Object 2nd Modification : " + obj);
Singleton st = (Singleton)deSerializeMe();
System.out.println("Deserialized successfully");
System.out.println("After Deserialization : " + st);
}
public static void serializeMe() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("d:\\SingletonData.txt"));
oos.writeObject(MySerializedSingleton.getInstance());
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object deSerializeMe() {
ObjectInputStream oin = null;
Object obj = null;
try {
oin = new ObjectInputStream(new FileInputStream("d:\\SingletonData.txt"));
obj = oin.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
class Singleton implements Serializable {
int i;
private static Singleton obj = null;
private Singleton() {
System.out.println("Executing constructor");
i=1;
}
public static Singleton getInstance() {
if(obj == null) {
obj = new Singleton();
}
System.out.println("An instance is returned");
return obj;
}
/*private void writeObject(ObjectOutputStream oos) {
try {
oos.writeInt(i);
} catch (Exception e) {
e.printStackTrace();
}
}
private void readObject(ObjectInputStream ois) {
try {
i = ois.readInt();
} catch (Exception e) {
e.printStackTrace();
}
}*/
public Object readResolve() {
System.out.println("Executing readResolve");
return Singleton.getInstance(); // FIXME
}
@Override
public String toString() {
return "Singleton [i=" + i + "]";
}
}
OUTPUT:
Executing constructor
An instance is returned
After NEW Object creation : Singleton [i=1]
Object modified
After Object 1st Modification : Singleton [i=5]
An instance is returned
Serialized successfully with object state : Singleton [i=5]
Object modified again
After Object 2nd Modification : Singleton [i=10]
Executing readResolve
An instance is returned
Deserialized successfully
After Deserialization : Singleton [i=10]
I know the current scenario will always return the same instance of Singleton with the latest Object's state.
I tried overriding the writeObject() and readObject() (commented in this above code) but not getting the desired result. i.e.
After Deserialization : Singleton [i=5]
But there is no reference of ObjectInputStream in readResolve() so that I can get the instance and update it with the serialized object's state before returning.
Please correct me if I am wrong in my conception and help me to solve this.
Thanks.
For Serializable and Externalizable classes, the readResolve method allows a class to replace/resolve the object read from the stream before it is returned to the caller. By implementing the readResolve method, a class can directly control the types and instances of its own instances being deserialized.
Serialization:- Serialization can also cause breakage of singleton property of singleton classes. Serialization is used to convert an object of byte stream and save in a file or send over a network.
Prevent Singleton Pattern From Cloning To overcome the above issue, we need to implement/override the clone() method and throw an exception CloneNotSupportedException from the clone method. If anyone tries to create a clone object of Singleton , it will throw an exception, as shown in the below code.
Here's how it can be achived:
public class Singleton implements Serializable {
private static Singleton instance = new Singleton();
private int i;
public static Singleton getInstance() {
return instance;
}
private Singleton() {
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
instance = this;
}
private Object readResolve() {
return instance;
}
public static void main(String[] args) throws Throwable {
Singleton s = Singleton.getInstance();
s.i = 5;
ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
oos.writeObject(getInstance());
oos.close();
s.i = 7; //modified after serialization
InputStream is = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
Singleton deserialized = (Singleton) ois.readObject();
System.out.println(deserialized.i); // prints 5
}
}
The best way to implement a Serializable
Singleton is to use an Enum.
From Joshua Bloch's Effective Java:
"This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton."
Save yourself some time and use an Enum.
Refer this question for more discussion on the same topic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With