Java Serialize and Deserialize Object

0

The process of converting objects in memory into sequence of bytes is known as serialization. The serialization process converts contents of the objects in memory with the description of the contents (known as metadata). When the object has references to other objects, the serialization mechanism also includes them as part of the serialized bytes.

Implement Serializable

You can serialize objects of all classes provided the classes implement the Serializable interface. A class is not serializable by default. If you don’t implement the Serializable interface and try to serialize the object, java.io.NotSerializableException will be thrown. Let’s now see an example. Message:

package com.javarticles.strings;

import java.io.Serializable;

public class Message implements Serializable {
    private String payload;
    private Integer id;
    private MessageMetadata metadata;

    public Message(String payload, Integer id, MessageMetadata metadata) {
        this.payload = payload;
        this.id = id;
        this.metadata = metadata;
    }

    public String getPayload() {
        return payload;
    }

    public Integer getId() {
        return id;
    }

    public MessageMetadata getMetadata() {
        return metadata;
    }
    
    public String toString() {
        return "Payload(" + payload + "), id( " + id + "), " + metadata;
    }
}

MessageMetadata:

package com.javarticles.strings;

import java.io.Serializable;

public class MessageMetadata implements Serializable {
    private String priority;
    private String origin;
    private MessageKind messageKind;
    private double msgVer = 1.2;

    public MessageMetadata(String priority, String origin,
            MessageKind messageKind) {
        super();
        this.priority = priority;
        this.origin = origin;
        this.messageKind = messageKind;
    }

    public String getPriority() {
        return priority;
    }

    public String getOrigin() {
        return origin;
    }

    public MessageKind getMessageKind() {
        return messageKind;
    }

    public double getMsgVer() {
        return msgVer;
    }
    
    public String toString() {
        return "messageKind(" + messageKind + "), priority(" + priority + "), origin(" + origin + "), msgVer(" + msgVer + ")";
    }
}

MessageKind:

package com.javarticles.strings;

public enum MessageKind {
    INSERT,UPDATE,DELETE
}

Transient member variable

Suppose you want to serialize an object that contains an unserializable class member, for example, a database entity. We do not want to serialize entity object as it is enough to serialize stuff which can help us to retrieve the entity back. Java offers a keyword known as transient, if a member is declared as transient then it won’t get serialized so their values are lost after deserialization. Let’s introduce a new class called Entity. Entity:

package com.javarticles.strings;

public class Entity {

}

We will modify Message class to hold a reference to Entity and declare it with transient keyword. Message:

package com.javarticles.strings;

import java.io.Serializable;

public class Message implements Serializable {
    private String payload;
    private Integer id;
    private MessageMetadata metadata;
    private transient Entity entity = new Entity();

    public Message(String payload, Integer id, MessageMetadata metadata) {
        this.payload = payload;
        this.id = id;
        this.metadata = metadata;
    }

    public String getPayload() {
        return payload;
    }

    public Integer getId() {
        return id;
    }

    public MessageMetadata getMetadata() {
        return metadata;
    }
    
    public String toString() {
        return "Payload(" + payload + "), id( " + id + "), " + metadata;
    }
}

Adding serialVersionUID

If you don’t define serialVersionUID the compiler will issue a warning.

The serializable class Message does not declare a static final serialVersionUID field of type long

You can either use the default serial version ID which is 1 or let JVM generate one for you based on the class behavior. It is requited to make sure that we don’t deserialize a wrong version of the class. Also, defining serialVersionUID enables the serialized object to work across different JVM implementations seamlessly thus we can send it across the wire from one system to another and it will work without any issue once deserialized in the second JVM. Message:

package com.javarticles.strings;

import java.io.Serializable;

public class Message implements Serializable {
    private static final long serialVersionUID = 5372783962512258254L;
    private String payload;
    private Integer id;
    private MessageMetadata metadata;
    private transient Entity entity = new Entity();

    public Message(String payload, Integer id, MessageMetadata metadata) {
        this.payload = payload;
        this.id = id;
        this.metadata = metadata;
    }

    public String getPayload() {
        return payload;
    }

    public Integer getId() {
        return id;
    }

    public MessageMetadata getMetadata() {
        return metadata;
    }
    
    public String toString() {
        return "Payload(" + payload + "), id( " + id + "), " + metadata;
    }
}

MessageMetadata:

package com.javarticles.strings;

import java.io.Serializable;

public class MessageMetadata implements Serializable {
    private static final long serialVersionUID = 868686920622607488L;
    private String priority;
    private String origin;
    private MessageKind messageKind;
    private double msgVer = 1.2;

    public MessageMetadata(String priority, String origin,
            MessageKind messageKind) {
        super();
        this.priority = priority;
        this.origin = origin;
        this.messageKind = messageKind;
    }

    public String getPriority() {
        return priority;
    }

    public String getOrigin() {
        return origin;
    }

    public MessageKind getMessageKind() {
        return messageKind;
    }

    public double getMsgVer() {
        return msgVer;
    }
    
    public String toString() {
        return "messageKind(" + messageKind + "), priority(" + priority + "), origin(" + origin + "), msgVer(" + msgVer + ")";
    }
}

Implement writeObject() and readObject()

If you want to customize the process of serialization, you can implement readObject() and writeObject(). Both of these methods are private methods. JVM verifies if you have implemented these methods. If yes, it will use them to serialize and deserialize. MessageObj:

package com.javarticles.strings;

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

public class MessageObj implements Serializable {
    private static final long serialVersionUID = 5372783962512258254L;
    private String payload;
    private Integer id;
    private MessageMetadataObj metadata;
    private transient Entity entity = new Entity();

    public MessageObj(String payload, Integer id, MessageMetadataObj metadata) {
        this.payload = payload;
        this.id = id;
        this.metadata = metadata;
    }

    public String getPayload() {
        return payload;
    }

    public Integer getId() {
        return id;
    }

    public MessageMetadataObj getMetadata() {
        return metadata;
    }
    
    public String toString() {
        return "Payload(" + payload + "), id( " + id + "), " + metadata;
    }
    
    private void writeObject(ObjectOutputStream os) throws IOException {
        System.out.println("Serialize Message using writeObject()");
        os.writeObject(metadata);
        os.writeInt(id);
        os.writeUTF(payload);        
    }
    
    private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
        System.out.println("Deserialize Message using readObject()");
        metadata = (MessageMetadataObj) is.readObject();
        id = is.readInt();
        payload = is.readUTF();
    }
}

MessageMetadataObj:

package com.javarticles.strings;

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

public class MessageMetadataObj implements Serializable {
    private static final long serialVersionUID = 868686920622607488L;
    private String priority;
    private String origin;
    private MessageKind messageKind;
    private double msgVer = 1.2;

    public MessageMetadataObj(String priority, String origin,
            MessageKind messageKind) {
        super();
        this.priority = priority;
        this.origin = origin;
        this.messageKind = messageKind;
    }

    public String getPriority() {
        return priority;
    }

    public String getOrigin() {
        return origin;
    }

    public MessageKind getMessageKind() {
        return messageKind;
    }

    public double getMsgVer() {
        return msgVer;
    }
    
    public String toString() {
        return "messageKind(" + messageKind + "), priority(" + priority + "), origin(" + origin + "), msgVer(" + msgVer + ")";
    }
    
    private void writeObject(ObjectOutputStream os) throws IOException {
        System.out.println("Serialize Metadata using writeObject()");
        os.writeDouble(msgVer);
        os.writeUTF(priority);
        os.writeUTF(origin);
        os.writeUTF(messageKind.name());        
    }
    
    private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
        System.out.println("Deserialize Metadata using readObject()");
        msgVer = is.readDouble();
        priority = is.readUTF();
        origin = is.readUTF();
        messageKind = MessageKind.valueOf(is.readUTF());
    }
}

JavaCustomSerializableExample:

package com.javarticles.strings;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class JavaCustomSerializableExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        MessageMetadataObj metadata = new MessageMetadataObj("High", "Database", MessageKind.UPDATE);
        MessageObj message = new MessageObj("Hello!", 9339, metadata);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(baos);
        System.out.println("Serialize "  + message);
        out.writeObject(message);
        byte[] b = baos.toByteArray();
        out.close();

        ByteArrayInputStream bais = new ByteArrayInputStream(b);
        ObjectInputStream in = new ObjectInputStream(bais);
        Object obj = in.readObject();
        in.close();
        System.out.println("Deserialized object: " + obj);
    }  
}

Output:

Serialize Payload(Hello!), id( 9339), messageKind(UPDATE), priority(High), origin(Database), msgVer(1.2)
Serialize Message using writeObject()
Serialize Metadata using writeObject()
Deserialize Message using readObject()
Deserialize Metadata using readObject()
Deserialized object: Payload(Hello!), id( 9339), messageKind(UPDATE), priority(High), origin(Database), msgVer(1.2)

Download the source code

This was an example about Java serialization and deserialization.

You can download the source code here: javaSerializableExample.zip
Share.

Comments are closed.