How to Serialize Object in Java - Serialization Example

Serialization is one of the important but confusing concept in Java. Even experienced Java developer struggle to implement Serialization correctly. The Serialiation mechamism is provided by Java to save and restore state of an object programatically. Java provides two classes Serializable and Externalizable in java.io package to facilitate this process, both are marker interface i.e. an interface without any methods. Serializing an Object in Java means converting into a wire format so that you can either persists its state in a file locally or transfer it to another client via the network, hence it become an extrememly important concept in distributed applications running across several JVMs. There are other features in Java e.g. Remote Method Invocation (RMI) or HttpSession in Servlet API which mandates the participating object should impelment Serializable interface because they may be transffered and saved across the network.

In this article, I have tried to explain the concept and process of Serialization by taking a simple example of a general purpose object in Java. We have a class called Shoe, which represents a Shoe, have instance variable to represent id, color, and size and staic variable to represent brand. I have included both transient and static variable to prove that those fields are not saved during Serialization process.

You can also read Head First Java to learn more about subtle details of Serialization in Java. They have covered the serilization topic just right, neither too much detail nor trivial explanation. I have learned a lot of useful details from there.

I have also explained the reverse process of Serialization to restore the state of object i.e. de-serialization and why SerialVersionUID is important for any serializable class. Once we restore the object we print it's state to compare values before serialization. This will give you clear idea about how you can save and restore objects in Java.



Java Program to Serialize an Object using Serializable interface

Here is our Java program to demonstrate how to serialize and de-serialize an object in Java. This program contains two classes Shoe and SerializationDemo, the first class is our POJO, we will create object of this class and serialieze it. The second class is our application class which contains the main() method, all the code to create object, saving it, and finally restoring it written inside main method.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.logging.Logger;

/**
 * Simple example of Serialization in Java. We first create a Shoe object, then
 * serializes it and finally restored it by using de-serialization.
 *
 * @author Javin Paul
 */
public class Pattern {

    public static void main(String args[]) throws IOException, ClassNotFoundException {
        Shoe whiteNikeShoe = new Shoe("Nike", 1000, 9, "WHITE", true);
        System.out.println("Before Serialization");
        whiteNikeShoe.print();

        // serializing shoe object
        writeShoe(whiteNikeShoe);

        // creating another Shoe with different brand
        Shoe blackAdidasShoe = new Shoe("Adidas", 2000, 8, "Black", true);
        
        
        // deserializing shoe object
        whiteNikeShoe = (Shoe) readShoe();

        System.out.println("After DeSerialization");
        whiteNikeShoe.print();
    }

    private static void writeShoe(Serializable shoe) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("shoe.ser")));
        oos.writeObject(shoe);
        oos.close();
    }

    private static Object readShoe() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("shoe.ser")));
        Object obj = ois.readObject();
        return obj;
    }

}

class Shoe implements Serializable {

    // static final variable
    private static final long serialVersionUID = 40L;
    private static final Logger logger = Logger.getLogger(Shoe.class.getName());

    // static variable but not final
    private static String _brand;

    // instance variable
    private int _id;
    private int _size;
    private String _color;

    // transient variable
    private transient boolean _isRunningShoe;

    // non serializable field
    Thread _thread;

    public Shoe(String brand, int id, int size, String color, boolean isRunningShoe) {
        System.out.println("Inside Constructor");
        _brand = brand;
        _id = id;
        _size = size;
        _color = color;
        _isRunningShoe = isRunningShoe;

    }

    public String brand() {
        return _brand;
    }

    public int id() {
        return _id;
    }

    public int size() {
        return _size;
    }

    public String color() {
        return _color;
    }

    public void print() {
        System.out.println("SerialVersionUID (final static field) : " + serialVersionUID);
        System.out.println("logger ((final static field) : " + logger);
        System.out.println("_brand (static field) : " + _brand);
        System.out.println("_id (instance variable) : " + _id);
        System.out.println("_size (instance variable) : " + _size);
        System.out.println("_color (instance variable) : " + _color);
        System.out.println("_isRunningShoed (transient variable) : " + _isRunningShoe);
        System.out.println("_thread (non-serializable field) : " + _thread);

    }

}

Output
Inside Constructor
Before Serialization
SerialVersionUID (final static field) : 40
logger ((final static field) : java.util.logging.Logger@42aab87f
_brand (static field) : Nike
_id (instance variable) : 1000
_size (instance variable) : 9
_color (instance variable) : WHITE
_isRunningShoed (transient variable) : true
_thread (non-serializable field) : null
Inside Constructor
After DeSerialization
SerialVersionUID (final static field) : 40
logger ((final static field) : java.util.logging.Logger@42aab87f
_brand (static field) : Adidas
_id (instance variable) : 1000
_size (instance variable) : 9
_color (instance variable) : WHITE
_isRunningShoed (transient variable) : false
_thread (non-serializable field) : null

A picture is worth a thousand word, so here is a diagram which explains the serialization and deserializtion process from a 10K feet view:

How to Serialize Object in Java - Serialization Example



Observation and Explanation

Now let's try to understand what happened when we serialize an instance of Shoe and later when we de-serialized it. I have created different types of variable in this class to show that whether their value is persisted or restored during Serialization or not. In Shoe class, we have two static final fields, SerialVersionUID, and Logger; their values are not persisted but because they are static. They are also initialized at the time of class loading, so they are fine. Also, because they are final, there is no danger of someone changing their value.

The SerialVersionUID is very important field for a serializable class and you should always define it. If you don't define then JVM will calculate this value by reading structure of class e.g. number of instance variable, their types etc. This means, next time you add another instance variable or you rmeove old one, you risk of getting a different SerialVersionUID and if that happens you won't be able to restore object saved by previous version of your program.

This has actually happend to us when one of the developer accidently removed the SerialVersionUID from one of the user preferences class and when user download and run the new version of our Java application, his preferences was all gone. He was a trader and for them their preferences means a lot, it was hard time to console and pacify him before we reverted back his GUI to previous version and restored his preferences. I am sure, you would never want to upset your clients and user.

Serialization is full of such details and I highly recommend to read Joshua Bloch advise on Effective Java related to Serialization before implementing it in your real world project. Those are invaluable piece of advice and key to successfully and correcly implment Serliazable in anything other than a demo program like this one.

Serialization best practices in Java


Now let's come to a simple, non-final static variable, its value is also not persisted during Serialization, that's why you see _brand=Nike before Serialization and _brand=Adidas after. Do you know why it happened? because when we created another instance of Shoe for Adidas, we reset value of this variable to "Adidas", and since the constructor is not called during deserialization, and class is not loaded again, its value remains "Adidas". It could have been null if de-serialization would have taken place at another JVM instance.

Now let's see our three instance variables _id, _size, and _color, their values are persisted during serialization and restored during de-serialization. This is why we see correct values for these three fields. Next is our transient variable isRunningShoe, this is tricky one, value of a transient variable is not stored during Serialization and that's why the value of isRunningShoe is incorrect after de-serialization.

It was true before but it became false after de-serialization. You would not have noticed this had that boolean variable was initialized as false, and you would have thought that value of the transient variable was saved and restored, which is not true. So beware of default values during Serialization, variables like static and transient will be initialized to their default value after de-serialization.

Last is our non-serializable instance variable _thread, which holds the instance of java.lang.Thread, which doesn't implement the Serializable interface. It's really interesting that default Serialization process doesn't complain about this variable, this can also be tricky to understand if don't pay enough attention. The reason was that variable didn't hold any value.

Now just initialize that variable as Thread _thread = new Thread() and re-run the program again. This time,will get the following Exception :

Exception in thread "main" java.io.NotSerializableException: java.lang.Thread
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
 at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
 at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.writeObject(Unknown Source)
 at SerializationDemo.writeShoe(HelloHP.java:42)
 at SerializationDemo.main(HelloHP.java:28)

Because Thread doesn't implement Serializable interface, you can not serialize it. This is a very common problem during maintenance of a legacy Java project. Suppose you have a Serializable class Employee, and later one developer introduced another instance variable Department, which is not Serializable. Do you know what will happen? The Employee can not be serialized anymore.

That's why I recommend putting Serialization alert in the source file of a Serializable classes, reminding them about not adding any variable which is not serializable or making it transient if they really need it. You can see Java Coding Guidelines for more coding best pracitces while writing Java application. It contains 75 recommendations for reliable and secure Java programs.

In short, we can say that :
  • The value of static variable is not persisted during Serialization.
  • Thetransient variables are not persisted as well.
  • Any NonSerializable field, which is not static or transient will break Serialization process by throwing ava.io.NotSerializableException.
  • The constructor of serializable class is not called during Serialization.

That's all about how to searialize an object in Java using Serializable interface. We have seen both saving and restoring object using serialization and de-serialization and also explored some key concepts related to how serialization works in Java. For example, transient and static variables are not saved during serialization, if you declare static variable, make sure it's not final, and to remember that constructor is not called during de-serialization process.

All these concepts are very important to implement serialization correctly in your pgoram. You can further read Effective Java by Joshua Bloch to understand effective serialization e.g. with custom binary formats.  All the items related to Serialization in this book is must read for any serious Java developer.


Other Java serialization tutorials you may like to explore
  • What Every Java developer should knwo about Serialization (read)
  • Difference between Serializable and Externalizable in Java? (answer)
  • Why should you use SerialVersionUID in Java? (answer)
  • Google Protocol Buffer - a fast alternative of serialization in Java? (tutorial)
  • Difference between transient and volatile variable in Java? (answer)
  • How to use transient variable in Serializable class? (answer)


Reference
Serializable Objects by Oracle



2 comments :

POOJA said...

Nice Article. It will be of great help if you can explain Externalization also in the same manner.

Emmanuel Keller said...

I just provided an example of Externalization implementation.

Post a Comment