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.
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
}
}