How to use Java ObjectOutputStream

Java has a very sophisticated yet simple to use serialization mechanism. It allows a program to transform an object to an array of bytes. In that form, the object can be persisted on the disk or transferred via a socket, or kept in memory for future use.

Later the object can be recreated from this array of bytes for further use.

Process

In order to be able to persist an object, it has to be serializable. That means

  • The class itself must implement the java.io.Serializable interface
  • All the embedded attributes, except the ones marked transient must be either primitive variables (int, long, etc, or instances of a serializable class)
  • The class must have a default constructor, same the embedded attributes of type object.

Then an instance of java.io.ObjectOutputStream is created, its method writeObject with our object as a parameter, and that’s it.

The ObjectOutputStream constructor takes one parameter, of type OutputStream. The ObjectOutputStream class knows how to get an object and transform it in an array of bytes. But from there, you need to get those bytes and process them further, either to have them written in a file on the disk, or store them in memory in a byte array etc.

In our case, we pass those bytes to a FileOutputStream, who behaves like a stream and knows how to deal with regular disk files.

The Code

Here is the code - two classes, one the main class that contains the functionality and a data class that is serializable and has all the attributes serializable as well.

The main class

package com.proghowto.outputstream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class Main {
	public static void main(String[] args) {
		try {
			new Main().writeData();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void writeData() throws IOException {
		// prepare the data
		DocData current = new DocData();
		current.setStart(12);
		current.setValue(23.3);
		ArrayList data = new ArrayList<>();

		for (int count = 0; count < 12; count++) {
			data.add("current value: " + count);
		}

		current.setInfo(data);

		// choose the file to be written
		FileOutputStream stream = new FileOutputStream("c:\\temp\\stream.dat");
		ObjectOutputStream out = new ObjectOutputStream(stream);

		out.writeObject(data);

		// flush and close both streams
		out.flush();
		out.close();

		stream.flush();
		stream.close();
	}
}

The data class

Please note the default constructor and the fact the class implements java.io.Serializable. The serialVersionUID is part of the picture; not declaring it in a serializable class will get you a warning.

package com.proghowto.outputstream;

import java.io.Serializable;
import java.util.ArrayList;

public class DocData implements Serializable {
	private static final long serialVersionUID = 2988633147597960409L;

	private int start;
	private double value;
	private ArrayList info;

	public DocData() {
		info = new ArrayList();
	}

	public DocData(int start, double value, ArrayList info) {
		this();

		setStart(start);
		setValue(value);

		setInfo(info);
	}

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public double getValue() {
		return value;
	}

	public void setValue(double value) {
		this.value = value;
	}

	public ArrayList getInfo() {
		return info;
	}

	public void setInfo(ArrayList data) {
		this.info.clear();

		if (data != null) {
			this.info.addAll(data);
		}
	}

}

The final result

Here is the obtained file (hex representation, to give you a better idea)
hex

Some recommendations

If you create one file with some serialized data, serialize only one object per file. It is simple, if you got many objects, wrap them in another serializable object and go for it. You got an array of same class objects? Do the same, put them in an ArrayList, wrap that in a nice serializable wrapper (I know the ArrayList is serializable in itself, but wrapping them in a specialized object will make your solution more readable)

Create an approach for consistently handling the serializable status of your classes - like extending all your classes from already serializable ones or from a main base class that implements serializable.