An option when you want to customize serialization is to use serialization proxies: instead of your "real" object you create a substitute that is serialized instead. The serialization framework uses the writeReplace()/readResolve()
methods, which allow you to do exactly this.
This is roughly what it looks like:
public class Foo implements Serializable {
private final String bar;
private final String baz;
private static class FooProxy implements Serializable {
private final String barBaz;
private FooProxy(Foo foo) {
this.barBaz = foo.bar + "|" + foo.baz; //don't do this for real
}
private Object readResolve() {
String [] arr = this.barBaz.split( "|" );
return new Foo(arr[0], arr[1]);
}
}
private Object writeReplace() {
return new FooProxy(this);
}
// this method is required to stop a maliciously constructed serialized form to be deserialized
private void readObject(ObjectInputStream ois) throws InvalidObjectException {
throw new InvalidObjectException( "Use a proxy." );
}
}
So every time Foo
is to be serialized, it is replaced with a FooProxy
object that has completely different fields, and every time FooProxy
is deserialized, it's replaced with a corresponding Foo
.
The advantage of this technique is that you can separate the serialized form from the internal representation completely, allowing you to change the internal representation arbitrarily, so long as it can be rebuilt from the serialized form.