public class Pojo implements Serializable {
private static ConcurrentMap
private String id;
private Pojo(String id) {
this.id = id;
}
public static Pojo getInstance(String id) {
Pojo pojo = instances.get(id);
if (pojo != null) {
return pojo;
} else {
Pojo newPojo = new Pojo(id);
pojo = instances.putIfAbsent(id, newPojo);
if (pojo == null) {
pojo = newPojo;
}
}
return pojo;
}
(...snip... equals and hashcode methods provided)
}So, when I create a unit test looking something like this:
public void shouldBeSingleton() {
Pojo pojo1 = Pojo.getInstance("id");
Pojo pojo2 = Pojo.getInstance("id");
assertTrue(pojo1 == pojo2);
}
..then the test passes.
Fine. By insisting that clients of this object use the static factory method, then I know that I can control the instances that I create. However, is this true? Turns out that if I test serializing this object to and from a byte array stream, then a simple assertTrue(original == copy) will fail.
The reason? What happens is that on deserializing the stream, a copy of the object is instantiated and then the fields are set, but the deserializing code does not "know" about the getInstance() method on the class.
Fortunately, you can tell it via the readResolve() mechanism. The readResolve() method is applied by the default readObject() implementation specified in the Java spec.
private Object readResolve() {
return Pojo.getInstance(this.id);
}
return Pojo.getInstance(this.id);
}
One problem of this method is that on deserialization an object is created and then discarded. This may cause garbage collection problems if you're doing this a lot.
Presumably if you provide a readObject() method then you might be able to avoid creating that object at all, so I'll look at that next...