The best way to achieve performance on Serialization, is to use Externalization without using writeObject.
Example 18.1. Externalization Code
public class FirstClass implements Externalizable
{
SecondClass secondClass;
public void writeExternal(ObjectOutputStream out)
{
secondClass.writeExternal(out);
}
public void readExternal(ObjectInputStream inp)
{
secondClass = new SecondClass();
secondClass.readExternal(inp);
}
}
class SecondClass implements Externalizable
{
String str;
public void writeExternal(ObjectOutputStream out) { out.writeUTF(str); }
public void readExternal(ObjectInputStream inp) { str = inp.readUTF(); }
}
This is because writeObject will call a heavy discovery meta data for reflection and serialization's constructors. Dealing directly with the life cycle of objects on externalization routines (calling new) will save you from execution this meta code.
Of course there are situations where you have to use writeObject/readObject, specially if the written object was already described as part of other object (for solving circular references), but most of times when doing writeExternal routines you can guarantee the life cycle of objects.
A rule of thumbs is always define serialVersionUID.
If you don't specify the uniqueID for the object, you can't guarantee version compatibility as minor changes could end up in different serialVersionUID, as they would be calculated according to rules specified on this URL:
http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/class.html#4100
For an externalizable class, writeExternal and readExternal will have to control its version compatibility.
ObjectInputStream encapsulates Streaming in such way that if you try to read more fields from a readExternal method, you would get an EOFException. You could use the exception to determine if the end of a streaming was reached, like in the example
Example 18.3. writeExternal/readExternal among different versions
public void writeExternal(ObjectOutputStream out)
{
out.writeUTF("FirstString");
// code added in a newer version
out.writeUTF("SecondString");
}
public void readExternal(ObjectInputStream inp)
{
String str1 = inp.readUTF();
try
{
String str2 = inp.readUTF();
}
catch (EOFException e)
{
}
}
On the example above if an older version was used to write the object an EOFException would happen and it would be ignored. This would guarantee compatibility between different versions.
Any change made to an Externalizable class will be compatible as long as its read and writeExternal methods are compliant.
Serialization's specification describe lots of scenarios on exchanging information between different class versions:
http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html
Basically there is one simple and basic rules that will summarize the list above
Add fields, don't delete them.
You need to take extra care when adding fields if the same Class is used back and forth different versions. For example a Class that is for communications on both sides.
The following URL lists all the possible situations where a class will and won't be compatible.
http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html