Presents your JAVA E-NEWSLETTER for May 29, 2003 <-------------------------------------------> EXPLORE THE INS AND OUTS OF SERIALIZATION Serialization is part of the java.io package and is used to translate objects into a stream of bytes. During serialization, an instance is transformed into a set of bytes representing the object. These bytes can be written to files for later use, sent across a network connection to other applications, used to construct copies of the original object, and so on. If you have a class that you want to be serializable, then you declare that your class implements java.io.Serializable and provide a no argument constructor. The Serializable interface declares no methods, so there's nothing else for your class to do. If you have a simple bean-like class that only has primitive and Serializable objects for properties, then there's nothing else for you to do. When you ask for your objects to be serialized to or from a series of bytes, Java takes care of all the details for you. TWO PROBLEMS YOU MAY EXPERIENCE Serialization can become more complicated. There are two common issues you may encounter with serialization: class versioning and complex objects. Versioning is probably the first problem you'll run into. For instance, if you add a method or property to your class after you serialize instances to a disk and then try to read the serialized instances back into memory later, you'll get a java.io.InvalidClassException. You get this error because your class's version has changed. There are ways to deal with this problem, but the solution takes some extra work on your part. For more details, check out the Java Object Serialization Specification. The second potential problem is if your class has state information that the virtual machine wouldn't know how to serialize. In that case, you can take over the responsibility for reading and writing instances of your class by implementing the two methods: private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; Notice that the methods are private. Serialization is special. If you want to see what's going on, look at the source code for java.io.ObjectOutputStream and java.io.ObjectInputStream and make sure you read the javadoc for java.io.Serializable in full. http://java.sun.com/j2se/1.4.1/docs/guide/serialization/spec/serialTOC.doc.html Here's a complete serialization example for you to play with: import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Random; public class SerializableTipHelper { private static final String STORE_FILE = "bytes.out"; private static final boolean VERBOSE = true; public static void main(String[] args) { if ( args.length != 1 && args.length != 2 ) { System.out.println("use: SerializableTipHelper (read|write) [numberToWrite]"); return; } if ( args[0].equals("write") ) { try { write(Integer.parseInt(args[1])); } catch (IOException e) { e.printStackTrace(); } } // defaults to read else { try { read(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } public static void read() throws IOException, ClassNotFoundException { ObjectInputStream in = new ObjectInputStream(new FileInputStream(STORE_FILE)); int numRead = 0; Object o = null; try { while ( (o = in.readObject()) != null ) { numRead++; if ( VERBOSE ) { System.out.println("read " + numRead + ": " + o); } } } catch (EOFException e) { // suppress } } public static void write(int num) throws IOException { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(STORE_FILE)); Random rand = new Random(System.currentTimeMillis()); for (int i = 0; i < num; i++) { SerializableTip st = new SerializableTip(); st.setAge(rand.nextInt(1000)); st.setEmployed(rand.nextBoolean()); st.setName("instance-" + i); Employee e = new Employee(); e.setId(rand.nextInt()); e.setName("employee-" + i); st.setEmployee(e); if ( VERBOSE ) { System.out.println("writing: " + st); } out.writeObject(st); } out.close(); } } class SerializableTip implements Serializable { private String name; private int age; private boolean employed; private Employee employee; private int weight; public int getAge() { return age; } public String getName() { return name; } public void setAge(int i) { age = i; } public void setName(String string) { name = string; } public boolean isEmployed() { return employed; } public void setEmployed(boolean b) { employed = b; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } public String toString() { StringBuffer me = new StringBuffer(); me.append("[").append(super.toString()) .append(",name=").append(this.name) .append(",age=").append(this.age) .append(",employed=").append(this.employed) .append(",employee=").append(this.employee) .append("]"); return me.toString(); } public int getWeight() { return weight; } public void setWeight(int i) { weight = i; } } class Employee implements Serializable { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public java.lang.String getName() { return name; } public void setName(java.lang.String name) { this.name = name; } public String toString() { StringBuffer me = new StringBuffer(); me.append("[").append(super.toString()) .append(",id=").append(this.id) .append(",name=").append(this.name) .append("]"); return me.toString(); } } ----------------------------------------