views:

791

answers:

6

In an interview the interviewer asked me the following question: is it possible to serialize a singleton object? I said yes, but in which scenario should we serialize a singleton?

And is it possible to design a class whose object can not be serialized?

+1  A: 

i said yes

Not by default. Next to implementing java.io.Serializable you need to override readObject() and writeObject() readResolve() methods, because you cannot serialize static fields. A singleton holds its instance in a static field.

but in which scenario we should serialize a singleton.

No useful real world scenario comes to mind actually. A singleton usually doesn't change of state throughout its lifetime nor contains any state which you'd like to save/restore. If it did, then it was already wrong to make it a singleton.

Two real world examples of singleton pattern in Java SE API are java.lang.Runtime#getRuntime() and java.awt.Desktop#getDesktop(). None of them implements serializable. It also doesn't make any sense because they right returns the right/desired/expected instance on every call. If you serialize and deserialize, you may end up with multiple instances. If you switch from environment in meanwhile, the instance may not work at all.

And is it possible to design a class whose object can not be serialized.

Yes. Just don't let the class implement java.io.Serializable interface.

BalusC
All you need is a reference to the instance, such as those handed out by a getInstance() method.
Michael Borgwardt
@BalusC: Actually you need to override `readReplace()` in order to return a single instance if deserialized multiple times.
axtavt
@BalusC, I don't think that you necessarily have to implement `writeObject(java.io.ObjectOutputStream)`.
Daniel Trebbien
@axtavt: interesting, never heard about this one before. Regardless, it makes simply no sense to serialize a singleton. It shouldn't have any state you'd like to save/restore/change.
BalusC
@Daniel: exactly, what's the benefit of `readObject`/`readReplace` then?
BalusC
@BalusC: I meant `readResolve`. Like here: http://www.javalobby.org/java/forums/t17491.html
axtavt
@BalusC: Having state is the main reason for singletons to exist in the first place; if it has no state, you might as well just use static methods.
Michael Borgwardt
@Michael: I mean, *a* state *which* you **would like** to save/restore/change.
BalusC
@BalusC, I'm not sure what you are asking. I agree that for this problem, `readObject` and `readReplace` are necessary, but not necessarily `writeObject` http://stackoverflow.com/questions/2958863/interview-question-about-java-serialization-and-singletons/2959481#2959481
Daniel Trebbien
@Daniel: true, it's possible, but how does it *make sense* in real world?
BalusC
@Daniel, implementing writeObject makes it so that the objects referenced by the Singleton don't themselves have to implement Serializable and are not serialized - since the serialized state is not used (except in Michael's example) why increase the binary size of the serialized object that reference it?
Yishai
@BalusC and @Yishai: I see your point. Most real-world singleton classes have non-serializable data, in which cases `writeObject` is necessary.
Daniel Trebbien
+11  A: 

in which scenario we should serialize a singleton.

Imagine you have a long-running app and want to be able to shut it down and later continue at the point where it was shut down (e.g. in order to do hardware maintenance). If the app uses a singleton that is stateful, you'd have to be able to save and restore the sigleton's state, which is most easily done by serializing it.

And is it possible to design a class whose object can not be serialized.

Very simple indeed: just don't implement Serializable and make the class final

Michael Borgwardt
+1: but i have a question, should we avoid serializing static fields ? It looks like bad design in general right ?
LB
@LB, it's not just bad design, it doesn't generally make sense semantically. Static fields are not associated with an instance. Deserialization is concerned with populating an instance. But the bad design IMO was in having class state at all: state should be limited to instances.
Mark Peters
A: 

A class that is serializable can be instantiated by deserializing it, allowing for multiple instances, making it not a singleton.

to your second question, from the java doc for java.io.Serializable

Serializability of a class is enabled by the class implementing the java.io.Serializable interface.

So to implement a class which is not serializable, don't implement Serializable.

Angelo Genovese
But if the class implements `readObject(java.io.ObjectInputStream)` to set the static reference to the single instance, and `readResolve()` to return the single instance (otherwise `this`), then you can still ensure that only one instance exists in the VM at any given time (assuming proper synchronization).
Daniel Trebbien
+3  A: 

The problem with serializing a singleton is that you end up with two, the original and the deserialized copy.

The most obvious way to prevent serialization is to simply not implement serializable. However, sometimes you will want your singleton to implement serializable so that it can be referenced in a serialized object without issues.

If that is a problem, you have a few options. The best is to make the singleton a single member enum, if possible. that way the underlying Java implementation takes care of all the details.

If that is not possible, then you need to implement the appropriate readObject and writeObject methods to ensure that serialization does not make a separate copy.

Yishai
+2  A: 

The question should probably be better phrased as "is it possible to use serialization and deserialization with a singleton-pattern class C in a way that does not break the singleton pattern?"

The answer is basically yes:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;

public class AppState implements Serializable
{
    private static AppState s_instance = null;

    public static synchronized AppState getInstance() {
        if (s_instance == null) {
            s_instance = new AppState();
        }
        return s_instance;
    }

    private AppState() {
        // initialize
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        synchronized (AppState.class) {
            if (s_instance == null) {
                // re-initialize if needed

                s_instance = this; // only if everything succeeds
            }
        }
    }

    // this function must not be called other than by the deserialization runtime
    private Object readResolve() throws ObjectStreamException {
        assert(s_instance != null);
        return s_instance;
    }

    public static void main(String[] args) throws Throwable {
        assert(getInstance() == getInstance());

            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
            oos.writeObject(getInstance());
            oos.close();

            java.io.InputStream is = new java.io.ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(is);
            AppState s = (AppState)ois.readObject();
            assert(s == getInstance());
    }
}

but note that it is possible for multiple instances of AppState to exist using this code. However, only one is referenced. The others are eligible for garbage collection, created only by the deserialization runtime, so they don't exist for practical purposes.

For answers to your other two questions (In which scenario should we serialize a singleton? Is it possible to design a class whose object can not be serialized?), see @Michael Borgwardt's answer.

Daniel Trebbien
While, I don't see why anyone would do that, you are absolutely correct - it is possible to serialize a Singleton object while maintaining the 1 singleton per JVM singleton pattern.
emory
A: 

is it possible to serialize a singleton object?

It depends on how the singleton is implemented. If your singleton is implemented as an enum type with one element, then it is by default:

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding() { ... }
}

If your singleton is not implemented using a single-element enum type but, say using a static factory method (the variant is to use a public static final field):

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    public void leaveTheBuilding() { ... }
}

Then it is not sufficient to add implements Serializable to make it serializable, you must declare all instance fields transient (to prevent a serialization attack) and provide a readResolve method.

To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method (Item 77). Otherwise, each time a serialized instance is deserialized, a new instance will be created, leading, in the case of our example, to spurious Elvis sightings. To prevent this, add this readResolve method to the Elvis class:

// readResolve method to preserve singleton property
private Object readResolve() {
     // Return the one true Elvis and let the garbage collector
     // take care of the Elvis impersonator.
    return INSTANCE;
}

This is heavily discussed in Effective Java (which also shows the serialization attack):

  • Item 3: Enforce the singleton property with a private constructor or an enum type
  • Item 77: For instance control, prefer enum types to readResolve

in which scenario should we serialize a singleton

For example for temporary, short-term storage or for transporting objects over a network (with RMI, for example).

And is it possible to design a class whose object can not be serialized.

As others said, don't implement Serializable. And even if an object or one of its superclasses implements Serializable, you can still prevent it from being serialized by throwing a NotSerializableException from writeObject().

Pascal Thivent
If the `readResolve` method returns the static instance, then there doesn't seem to be a point to serializing and deserializing; why deserialize an `Elvis` if the end result is the same as calling `Elvis.getInstance()`?
Daniel Trebbien
@Daniel Why deserialize an `Elvis`? Well, what about: because you serialized it? Honestly, I don't see what is not clear in what I wrote or quoted (and I actually don't understand your comment).
Pascal Thivent
@Pascal Thivent: In the call to `readObject` of `ObjectInputStream`, the deserialization runtime first creates an `Elvis` instance using `defaultReadObject` or the `Elvis` class' `readObject` method, and then calls the `Elvis` class' `readResolve` method. Because your `readResolve` returns `INSTANCE` which was instantiated statically, the `Elvis` instance that was deserialized is discarded. Thus, the program would go through all of this work to serialize and deserialize the `Elvis` instance for nothing. It might have well just called `Elvis.getInstance()` because the end result is the same.
Daniel Trebbien
@Daniel *the Elvis instance that was deserialized is discarded* Yes and that's **exactly** the point. *Thus, the program would go through all of this work to serialize and deserialize the Elvis instance for nothing* You are assuming that serialization never happens on your back, which is not true (e.g. the singleton can be part of a graph, can be sent over the network) and you statement is thus invalid.
Pascal Thivent
@Pascal Thivent: If you take a look at the code in http://stackoverflow.com/questions/2958863/interview-question-about-java-serialization-and-singletons/2959481#2959481 , the `AppState` instance does not exist until someone asks for it either by deserializing an `AppState` or calling `AppState.getInstance()`. Using @Michael Borgwardt's example for why this might be useful, if the app deserializes the `AppState` first, then the deserialized `AppState` becomes *the* instance. Otherwise, the app can call `getInstance()` to obtain a default instance to be serialized later.
Daniel Trebbien
@Daniel I still don't get your point. The above code doesn't lazy load the singleton - which should be done using the [Initialization on Demand Holder (IODH) idiom](http://crazybob.org/2007/01/lazy-loading-singletons.html) BTW - and just works. If you have some concerns with it, test it yourself and/or write a mail to Joshua Bloch :)
Pascal Thivent