I was thinking about the purpose of Externalisation, given that you could simply label a property as transient
and prevent its serialisation. However, upon further research I found out that this approach (i.e. labelling as transient
) may not be ideal if you need to decide what's required at run-time. Theoretically, it makes sense to me. However, practically I don't see how Externalisation is more run-time friendly. I mean, you still have to decide what's required or not within the writeExternal()
and readExternal()
during the definition of the class. So, how is that more run-time friendly?
The document that highlighted this is as follows,
If everything is automatically taken care by implementing the Serializable interface, why would anyone like to implement the Externalizable interface and bother to define the two methods? Simply to have the complete control on the process. OKay... let's take a sample example to understand this. Suppose we have an object having hundreds of fields (non-transient) and we want only few fields to be stored on the persistent storage and not all. One solution would be to declare all other fields (except those which we want to serialize) as transient and the default Serialization process will automatically take care of that. But, what if those few fields are not fixed at design tiime instead they are conditionally decided at runtime. In such a situation, implementing Externalizable interface will probably be a better solution. Similarly, there may be scenarios where we simply don't want to maintain the state of the Superclasses (which are automatically maintained by the Serializable interface implementation).
public class Foo implements Externalizable{
private long userID;
private String userName;
private char[] userPassword;
private int age;
private boolean shouldSavePassword;
public void setSavePassword(boolean shouldSavePassword){
this.shouldSavePassword = shouldSavePassword;
}
void writeExternal(ObjectOutput out) throws IOException{
out.writeObject(userID);
out.writeObject(userName);
out.writeObject(shouldSavePassword);
if(shouldSavePassword){
out.writeObject(userPassword);
}
out.writeObject(age);
}
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
userID = in.readLong();
userName = (String) in.readObject();
shouldSavePassword = readBoolean();
if(shouldSavePassword){
userPassword = (char[]) in.readObject();
}
age = in.readInt();
}
}
Note how the field userPassword
is only serialized upon the runtime value of shouldSavePassword
. Had you declared the field transient, you have made the decision of whether to serialize or not a compile-time property, unable to be changed at runtime (unless via reflection).
The flexibility of Externalizable also allows you to determine your own serialization scheme, encrypting objects as necessary if they are sensitive.
Another usecase would potentially be the option to attach a one-way hash to the end of the class for maximum reliability. A field could determine whether or not to save the hash (since it's extra computation).
The bottom line is, transient
doesn't give you any runtime control over how serialization of your object will be done, merely that the field will or will not be serialized (as a compile-time parameter).
Disclaimer: The example given above is a terrible scheme to save passwords, do not use it for any production application. Plaintext passwords should be saved after passing through PBPDFs such as bcrypt, PBKDF#2 and scrypt.