Author: Mohammad J Iqbal

Mohammad J Iqbal

#Serialization: Converting objects into a stream of bytes

#Deserialization: reconstructing objects from those bytes

Why Serialization? Suppose you are playing a game and you are very excited about the stage you are already in but you have to leave the desk for some important task. You can pause the game and can resume from where you left off.

Second scenario, you are browsing in your web browser using multiple tabs and sudden you have crossed the window. When you start the browser again, you must feel good if you see all of your tabs are same and active as you left off. The objects states were saved to disk!

Third scenario, you are playing online games with your friends and your friend needs to react on your action basically the states of your objects: player, car, fighter jet etc. That means the game software might need to transfer your objects over the network and on the other side of the network, the objects’ states need to be reconstructed from bytes.

Let’s look back at the Linkedlist that I have written in my previous article and see how we can covert the Data Structure to a SerializableLinkedList.

package com.spsoft.list;

import java.io.Serializable;

public class SerializableLinkedList<E> extends IterableLinkedList implements Serializable {
    @java.io.Serial
    private static final long serialVersionUID = 876323262645176354L;

    /**
     * Saves the state of this {@code LinkedList} instance to a stream
     * (that is, serializes it).
     */
    @java.io.Serial
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();

        // Write out size
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (Node<E> x = first; x != null; x = x.next)
            s.writeObject(x.item);
    }

    /**
     * Reconstitutes this {@code LinkedList} instance from a stream
     * (that is, deserializes it).
     */
    @SuppressWarnings("unchecked")
    @java.io.Serial
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();

        // Read in size
        int size = s.readInt();

        // Read in all elements in the proper order.
        for (int i = 0; i < size; i++)
            addLast((E)s.readObject());
    }

}


In the above code I have extended the IterableLinkedList and implemented marker interface Serializable.

A marker interface is an empty interface which is used to indicate some features will be used in the class that implements the marker interface.

In this example, by using Serializable interface we are indicating that states of this class will be saved and may be restored.

serialVersionUID: the serialVersionUID is a unique identifier for a serializable class. It’s a field that developers can explicitly declare within a class to control versioning during serialization and deserialization. When an object is serialized, the serialVersionUID is also written to the stream of bytes along with the object’s data.

The primary purpose of serialVersionUID is to ensure that the serialized form of a class is compatible between different versions of that class. It helps in detecting incompatible changes made to the class that would prevent successful deserialization of previously serialized objects.

The methods writeObject and readObject will be used to serialize and deserialize the object in this class.

If we look at the methods we can see that we are writing all the nodes in the linked list for serializing and we are reading them back and adding to the list during deserialization process.

Let’s use the code below to test:


package com.spsoft.list;

import java.io.*;

public class SerializableLinkedListTest {
    public static void main(String args[]) throws FileNotFoundException {
        SerializableLinkedList<String> linkedList = new SerializableLinkedList<>();
        linkedList.addLast("Apple");
        linkedList.addLast("Banana");
        linkedList.addLast("Mango");
        //Write linkedList object to file
        try (var out = new ObjectOutputStream(new FileOutputStream("liknkedlist.ser"))){
            out.writeObject(linkedList);
            System.out.println("Serialization was done successfully");
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        try (var out = new ObjectInputStream(new FileInputStream("liknkedlist.ser"))){
            out.readObject();
            System.out.println("Deserialization was done successfully");
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

In the above code, we are saving the linkedList object to disk by calling out.writeObject(linkedList) and reading it back by calling out.readObject()

When we run the code, we get below output:

Output of the class SerializableLLinkedListTest

Follow Mohammad J Iqbal on LinkedIn