Serialization : Should I use it?

serialization-deserialization-in-java-object-streamsWhat is serialization? To answer this question I took a look at Wikipedia and edited their definition.

Serialization is the process of translating data structures or object state into a format that can be stored (e.g., in a file or transmitted across a network connection) and reconstructed later in the same or another computer environment. For many complex objects, such as those that make extensive use of references, this process is not straightforward (e.g., an object from a class that has fields made up of combinations of other classes. Serialization of object-oriented objects does not include any of their associated methods with which they were previously inextricably linked. For that purpose, other mechanisms (e.g., JSON, XML) are available. The opposite operation, extracting a data structure from a series of bytes, is named deserialization.

In a nutshell, serialization consists of putting together a set of bytes that represent the data associated with an object for use by the same or other process in the same or on a networked machine. The issue with this approach is that different machines may use different bytes orders so if the same object is written using a big-endian on a machine and then transferred to another that uses a little-endian, the data would not be useful.

Let’s take a look at a screen capture from an Eclipse IDE:

show <<< width: 3 height: 4 area: 12

show <<< width: 3 height: 4 area: 0

show <<< width: 3 height: 4 area: 0

The concepts for serialization in Java are quite simple. The rectangle1implementation is also simple. As you can deduct, the area of a rectangle with width 3 and height 4 resulting in an area of 12 is displayed. Following are two more displays without the area. Let’s first look at the code and then figure out what is happening and determine how the code should or should not be written.

The Java code follows:

package john.canessa.serialization.rectangle;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

/*

* rectangle class

*/

class Rectangle implements Serializable {

// **** serial version ID ****

private static final long serialVersionUID = 1L;

/*

* The keyword transient marks a member variable not to be serialized

* when it is persisted to streams of bytes. When an object is

* transferred through the network, the object needs to be ‘serialized’.

* Serialization converts the object state to serial bytes. Those bytes

* are sent over the network and the object is recreated from those bytes.

* Member variables marked by the java transient keyword are not

* transferred, they are lost intentionally.

*/

int           width;

int           height;

transient int        area;

/*

* constructor

*/

public Rectangle(int w, int h) {

this.width    = w;

this.height   = h;

this.area     = w * h;

}

/*

* write rectangle to file

*/

private void writeObject(ObjectOutputStream outStream) throws IOException {

outStream.defaultWriteObject();

}

//     /*

//     * read rectangle from file

//     */

//     private void readObject(ObjectInputStream inStream) throws ClassNotFoundException, IOException {

//            inStream.defaultReadObject();

//            this.area = this.width * this.height;

//     }

/*

* show

*/

public void show(Rectangle r) {

System.out.println(“show <<< width: ” + r.width + ” height: ” + r.height + ” area: ” + r.area);

}

}

public class Solution {

/*

* test code

*/

public static void main(String[] args) throws IOException, ClassNotFoundException {

final String fileName      = “c:\\temp\\rectangle.txt”;

int w         = 3;

int h         = 4;

Rectangle r = new Rectangle(w, h);

r.show(r);

// **** serialize object (rectangle) ****

FileOutputStream outFileStream           = new FileOutputStream(fileName);

ObjectOutputStream outOjectStream = new ObjectOutputStream(outFileStream);

outOjectStream.writeObject(r);

outOjectStream.close();

outFileStream.close();

// **** deserialize object (rectangle) ****

FileInputStream inFileStream             = new FileInputStream(fileName);

ObjectInputStream inObjectStream = new ObjectInputStream(inFileStream);

Rectangle rr = (Rectangle)inObjectStream.readObject();

inObjectStream.close();

inFileStream.close();

// **** show, fix and show read rectangle ****

rr.show(rr);

//            rr.area = rr.width * rr.height;

rr.show(rr);

}

}

The class Rectangle that implements Serializable contains three members (width, height and area) and four methods. The readObject() method has been commented out.

The main() method creates a rectangle of width 3 and length 4. The constructor sets the area to 12. Note that the area has a modifier transient. The definition is in the code.

The rectangle is serialized and written to a file. The file then is read. After reading the file (commented out) we generate the area for the rectangle. This was done to experiment with the modifier transient. If we comment the generation of the area we would have:

show <<< width: 3 height: 4 area: 12

show <<< width: 3 height: 4 area: 0

show <<< width: 3 height: 4 area: 12

hex_dumpIt would be better to have the area computed while deserializing the object. By the way, the binary hexadecimal dump of the c:\temp\rectangle.bin file follows:

AC ED 00 05 73 72 00 2E 6A 6F 68 6E 2E 63 61 6E 65 73 73 61 2E 73 65 72 69 61 6C 69 7A 61 74 69 6F 6E 2E 72 65 63 74 61 6E 67 6C 65 2E 52 65 63 74 61 6E 67 6C 65 46 80 42 F4 2A 01 7D 00 03 00 02 49 00 06 68 65 69 67 68 74 49 00 05 77 69 64 74 68 78 70 00 00 00 04 00 00 00 03 78

In ASCII we would have:

¬í..sr..john.canessa.serialization.rectangle.RectangleF€Bô*.}….I..heightI..widthxp……..x

Not easy to parse by hand, especially when deserialization would occur on a different machine and possibly with a different CPU architecture.

Let’s take a look at the contents of the console one more time:

show <<< width: 3 height: 4 area: 12

show <<< width: 3 height: 4 area: 12

This occurs by enabling the commented out method readObject() and removing the third call to show().

In conclusion, there are occasions one might serialize and then deserialize objects. Normally this should be done under control conditions. If the file would be consumed by an arbitrary client, there are better ways to get it done. Do not use serialization for data exchange. It is prone to errors.

In a future blog I will show how hibernate and ORM are useful to store and retrieve objects from a database.hibernate

As usual, if you have comments or questions regarding this or any other blog post, please send me a line via email. I will respond as soon as possible.

John

john.canessa@gmail.com

Leave a Reply

Your email address will not be published. Required fields are marked *