Re: implement writeObject how? serializable singleton how?
Tom Hawtin <usenet@tackline.plus.com> writes:
Frank Fredstone wrote:
Tom Hawtin <usenet@tackline.plus.com> writes:
Perhaps you are seeing the construction during static (class)
initialisation. When an object is deserialised the constructor of the
most derived non-serialisable class (possibly Object) is invoked by
the serialisation mechanism.
So, you and Chris Uppal's post as well, are agreeing that the
constructor is called during deserialization.
The constructor is not called for the deserialised copy. It is called
for the singleton copy.
If I don't implement readObject/writeObject:
MySingleton ms = (MySingleton) objectInputStream.readObject();
System.out.println("After deserialization");
prints
Constructing MySingleton
After deserialization
then after:
ms.instance();
it does not print "Constructing MySingleton".
That makes me think that the constructor is being called when it's
deserialized.
I'm not sure if I understand the distinction you are making between
the deserialized copy and the singleton copy.
I want an object that has a state that is initialized only once, as a
result of an external side-effect. I also want it to be possible for
that state to be serialized, without the state being "reinitialized"
(in the sense of being intitialized again by a specific block of code)
during deserialization. I want the state (the field values) restored,
without the code that initializes them during construction being
called.
private static MySingleton instance = null;
public static MySingleton instance() {
if (instance == null) {
instance = new MySingleton(true);
}
return instance;
}
This is not thread safe.
I should have used:
public static synchronized MySingleton instance() {
....
}
private void readObject(ObjectInputStream s) throws IOException {
try {
ObjectInputStream.GetField fields = s.readFields();
instance = (MySingleton) fields.get("instance", null);
But that doesn't change any current instance of MySingleton to the new
singleton. I suspect that a singleton is really not what you want (it
almost never is).
Is there a way to avoid the possibility of their being multiple copies
of an object due to deserialization?
I should also add a clone method that throws an exception
I'm treating serialization as some ugliness that allows you to violate
the interface of a class, and I want to do my best to make my class
survive that ugliness.
Anyway, proceeding on with deserialisation mutates the singleton, I
suggest just updating the actual singleton instance, and replacing
references to it in other deserialised object to the real version.
public class MySingleton implements java.io.Serializable {
private static final MySingleton INSTANCE = new MyInstance();
public static getInstance() {
return INSTANCE;
}
private String value;
private MySingleton() {
System.out.println("Constructing MySingleton");
}
public synchronized String getValue() {
return value;
}
public synchronized void setValue(String value) {
this.value = value;
}
private Object readResolve(java.io.ObjectInputStream s) {
// Copy data into real instance.
synchronized (INSTANCE) {
INSTANCE.value = this.value;
}
// Replace serial instance with the real one.
return INSTANCE;
}
}
That class does not contain constant values as it's "state" and is not
initialized by a side-effect that must be used to inititialize the
state once and only once, which is what I need.