Example 13. Test a serializable singleton
import java.io.*;
import org.apache.log4j.Logger;
import junit.framework.Assert;
import junit.framework.TestCase;
public class SingletonTest extends TestCase {
private Singleton sone = null, stwo = null;
private static Logger logger = Logger.getRootLogger();
public SingletonTest(String name) {
super(name);
}
public void setUp() {
sone = Singleton.INSTANCE;
stwo = Singleton.INSTANCE;
}
public void testSerialize() {
logger.info("testing singleton serialization...");
writeSingleton();
Singleton s1 = readSingleton();
Singleton s2 = readSingleton();
Assert.assertEquals(true, s1 == s2);
}
private void writeSingleton() {
try {
FileOutputStream fos = new FileOutputStream("serializedSingleton");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Singleton s = Singleton.INSTANCE;
oos.writeObject(Singleton.INSTANCE);
oos.flush();
}
catch(NotSerializableException se) {
logger.fatal("Not Serializable Exception: " + se.getMessage());
}
catch(IOException iox) {
logger.fatal("IO Exception: " + iox.getMessage());
}
}
private Singleton readSingleton() {
Singleton s = null;
try {
FileInputStream fis = new FileInputStream("serializedSingleton");
ObjectInputStream ois = new ObjectInputStream(fis);
s = (Singleton)ois.readObject();
}
catch(ClassNotFoundException cnf) {
logger.fatal("Class Not Found Exception: " + cnf.getMessage());
}
catch(NotSerializableException se) {
logger.fatal("Not Serializable Exception: " + se.getMessage());
}
catch(IOException iox) {
logger.fatal("IO Exception: " + iox.getMessage());
}
return s;
}
public void testUnique() {
logger.info("testing singleton uniqueness...");
Singleton another = new Singleton();
logger.info("checking singletons for equality");
Assert.assertEquals(true, sone == stwo);
}
}
The preceeding test case serializes Example 12's singleton and deserializes it twice. Then the test case checks to see if the deserialized singletons are the same object. Here's the test case output:
Buildfile: build.xml
init:
[echo] Build 20030422 (22-04-2003 11:32)
compile:
run-test-text:
[java] .INFO main: testing singleton serialization...
[java] .INFO main: testing singleton uniqueness...
[java] INFO main: checking singletons for equality
[java] Time: 0.1
[java] OK (2 tests)
Singleton sign-off
The Singleton pattern is deceivingly simple, especially for Java developers. In this article, I've demonstrated how Java developers implement singletons, considering multithreading, classloaders, and serialization. I've also shown how you can implement singleton registries that let you specify singleton classes at runtime.
This story, "How to navigate the deceptively simple Singleton pattern" was originally published by JavaWorld.