Saturday, 27 November 2010

Java Serialization Part 2

Great stuff. So we've proved that testing basic Java serialization isn't too hard. So, let's say that I've got a requirement to control instances of this basic object. I'm going to put a ConcurrentMap of instances within the object, make the constructor private and then provide a static factory method on the object to give me the instances.

public class Pojo implements Serializable {
    private static ConcurrentMap instances = new ConcurrentHashMap();

    private String id;

    private Pojo(String 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(;

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

Java Serialization Part 1

I wondered what my first post would be, and here it is. Java Serialization!

If I have a plain Java object that is serializable:

public class Pojo implements Serializable {

    private String id;

    public Pojo(String id) { = id;

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Pojo pojo = (Pojo) o;

        if (id != null ? !id.equals( : != null) return false;

        return true;

    public int hashCode() {
        return id != null ? id.hashCode() : 0;

...then how can I prove that it is serializable? Turns out that it's not that difficult at all. A quick Google, and I find this page which had some unit test code on it which I could modify:

    public void shouldSerializeAndDeserialize() throws Exception {
        // construct test object
        Pojo original = new Pojo("id");

        // serialize
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(out);

        byte[] pickled = out.toByteArray();
        InputStream in = new ByteArrayInputStream(pickled);
        ObjectInputStream ois = new ObjectInputStream(in);
        Object o = ois.readObject();
        Pojo copy = (Pojo) o;

        // test the result

In the next post, I'll discuss controlling instances of this simple object.