Monday, January 29, 2007

Notes on ObjectOutputStream.writeObject()

If you write the same object twice into the ObjectOutputStream using writeObject() method, typically you would expect that the size of the stream should increase approximately by the size of the object (and all the fields within that recursively). But it wouldn't happen so.

It is very critical to understand how writeObject() method works. It writes an object only once into a stream. The next time when the same object is written, it just notes down the fact that the object is already available in the same stream.

Let us take an example. We want to write 1000 student records into an ObjectOutputStream. We create only one record object, and plan to reuse the same record within a loop so that we save time on object creation. We will use setter methods to update the same object with next student's details. If we use writeObject() to carry out this task, changes made to all but the first student's records will be lost. (Go ahead and try the program given below)

To achieve the objective stated above, you must use writeUnshared() method call. (Change the writeObject() method to writeUnshared() method and convince yourself)

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.Serializable;

class StudentRecord implements Serializable {
public String name;
public String major;
}

public class ObjectStreamTest {
public static void main(String[] argv) throws IOException, java.lang.ClassNotFoundException {
// Open the Object stream.
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objectfile.bin"));

// Create the record that will be reused.
StudentRecord rec = new StudentRecord();

// Write the records.
rec.name = "John"; rec.major = "Maths";
oos.writeObject(rec);
rec.name = "Ben"; rec.major = "Arts";
oos.writeObject(rec);
oos.close();

// Read the objects back to reconstruct them.
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objectfile.bin"));
rec = (StudentRecord)ois.readObject();
System.out.println("name: " + rec.name + ", major: " + rec.major);
rec = (StudentRecord)ois.readObject();
System.out.println("name: " + rec.name + ", major: " + rec.major);
ois.close();
}
}

5 comments:

Onkar Joshi said...

Very nice example. Was stuck on it for a while and then I came across your post and cleared up a couple of misconceptions.

I'll soon write a little post about the same and a bit more on my blog.

Onkar Joshi.
http://onkarjoshi.wordpress.com/

Anonymous said...

Hi,

This blog entry helped me out a lot!

I'm working on a 3D FPS and I was using the writeObject method and wondering why I kept reading in the same #$^$%@ command over and over.

Now I realize why I should read the ENTIRE Java API spec for something like ObjectOutputStream (and not just scan for a method that looks like the one i want).

Thanks again for sharing your experiences with Serialization.

Barrera said...

i spent 4 hours to discover this
thank you

greets from brazil

Michael said...

I spent hours trying to find the reason why I kept writing the same object.
Thanks for pointing this out.

Anonymous said...

yes, great note. The same happened to me I waste almost 3 hours wondering was wrong, just up until and came across this note.