bio photo

Twitter Github

Java Serialization is a easy way to persist the state of Java Objects. However if the structure of the class changes the serialized bytes is invalidated by the changes. This article suggest how one could implement serialization with Externalizable with support for versions.

Consider a simple java class

public class SimpleObject implements Serializable {
        private int field1;
        private int field2;
}

If the structure of the class changes, then the serialized bytes becomes incompatible and you would get the dreaded ClassCastException

public class SimpleObject implements Serializable {
        //private int field1; removed
        private int field2;
        private int field3; //added
}

A good way to get complete control of the serialization and support version is by implementing Externalizable instead of Serializable.

Externalizable gives the programmer full control over how the class is serialized and de-serialized. It is common practice to add a version variable to support representations of the same class over time.

Consider first version of the same class

public class SimpleObject implements Externalizable {
        private int version=1;
        private int field1;
        private int field2;
        @Override
        public void readExternal(ObjectInput in) throws IOException,
                        ClassNotFoundException {
                version=in.readInt();
                if(version==1) {
                        field1=in.readInt();
                        field2=in.readInt();
                } else {
                        throw new IOException(Invalid Version);
                }
        }
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
                out.writeInt(version);
                out.writeInt(field1);
                out.writeInt(field2);
        }
}

Now if the next version of the class needs to add a String and remove field2 the class would look like

public class SimpleObject implements Externalizable {
        private int version=1;
        private int field1;
        //private int field2; removed
        private String version2String;
        @Override
        public void readExternal(ObjectInput in) throws IOException,
                        ClassNotFoundException {
                version=in.readInt();
                if(version==1) {
                        field1=in.readInt();
                        in.readInt();// ignore
                        version2String=“”;// initialize to default
                } else if (version==2) {
                        field1=in.readInt();
                        version2String=(String) in.readObject();
                } else {
                        throw new IOException(Invalid Version);
                }
        }
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
                out.writeInt(version);
                out.writeInt(field1);
                out.writeObject(version2String);
        }
}