Monday, November 8, 2010

The Externalizable interface

There might be times when you have special requirements for the serialization of an object. For example, you may have some security-sensitive parts of the object, like passwords, which you do not want to keep and transfer somewhere. Or, it may be worthless to save a particular object referenced from the main object because its value will become worthless after restoring.

You can control the process of serialization by implementing the Externalizable interface instead of Serializable. This interface extends the original Serializable interface and adds writeExternal() and readExternal(). These two methods will automatically be called in your object's serialization and deserialization, allowing you to control the whole process.

There is one major difference between serialization and externalization: When you serialize an Externalizable object, a default constructor will be called automatically; only after that will the readExternal() method be called. Listing C shows how you can use externalization.

Listing C

import java.io.*;
import java.util.*;

class Data implements Externalizable {
inti;
String s;
public Data() {
System.out.println("Data default constructor");
}
public Data(String x, int a) {
System.out.println("Second constructor");
s = x; i = a;
}
public String toString() {
return s + i;
}
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeObject(s);
out.writeInt(i);
}
public void readExternal(ObjectInput in) {
s = (String)in.readObject();
i = in.readInt();
}
public static void main(String[] args)
throws IOException, ClassNotFoundException {
Data d = new Data("String value",1514);
System.out.println(d);
ObjectOutputStream o = new ObjectOutputStream(
New FileOutputStream("data.out"));
o.writeObject(d);
o.close();

// Now deserialize
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("data.out"));
d = (Data)in.readObject();
}
}

If you inherit some class from a class implementing the Externalizable interface, you must call writeExternal() and readExternal() methods when you serialize or deserialize this class in order to correctly save and restore the object.

The "transient" keyword

If you don't need to save and restore any member variable (e.g., the password kept in a String object), the private modifier will not help you. Serialized information can be read in a file or in a captured network packet. You may implement the Externalizable interface, which is demonstrated in the previous paragraph. In this case, nothing is written automatically, and you can control the entire process.

However, serializable objects are much more convenient because everything is serialized there automatically. You can forbid serialization of any member variable object with the transient modifier. It tells the JVM: "Do not save and restore this field, please; somebody else will take care of this field." Listing D shows how it looks.

Listing D

import java.io.*;
import java.util.*;

class LoginCredentials implements Serializable {

private String username;
private transient String password;

LoginCredentials(String name, String password) {
username = name;
this.password = password;
}

public static void main(String[] args)
throws IOException, ClassNotFoundException {
LoginCredentials = new LoginCredentials("peter","mikhalenko");
}
}

No comments:

Post a Comment