Core Java

Serializable Java Example – How to serialize and deserialize objects

In this article, we will discuss what is Serializable in Java using examples and how to serialize and deserialize objects. Serialization in java is the process of converting an object into a stream of bytes.

You can also check this tutorial in the following video:

Java Serialization Tutorial – video

1. Introduction

De-serialization is the reverse process which converts a stream of bytes into an object. Java provides a Serializable marker interface, ObjectInputStream, and ObjectOutputStream classes to support both serialization and de-serialization. In this example, I will demonstrate:

  • Declare a Serializable class with or without a serialVersionUID.
  • Serialize an object into a byte stream via ObjectOutputStream.writeObject.
  • De-serialize a byte stream into an object via ObjectInputStream.readObject.

2. Technologies Used

The example code in this article was built and run using:

  • Java 11
  • Maven 3.3.9
  • Eclipse Oxygen

3. Maven Project

3.1 Dependencies

I will include JDK11 in the pom.xml.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>java-zheng-demo</groupId>
	<artifactId>serialization-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<release>11</release>
				</configuration>
			</plugin>
		</plugins>
	</build>
	
</project>

3.2 SerializeManager

In this step, I will create a SerializeManager class which has two methods:

  • serializeObjectAndSavetoFile(Object input) – invokes ObjectOutputStream.writeObject to serialize an object and writes the byte stream into a file.
  • readByteStreamFromFileAndDeSerializeToObject(String filename) – reads the byte stream from a file and de-serializes into an object with ObjectInputStream.readObject.

SerializaManager.java

package jcg.zheng.demo.serialization;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializeManager {

	private static final String FILE_NAME_PREFIX = "ByteStream_";
	private static final String READ_OBJECT = "\nto an Object: ";

	public Object readByteStreamFromFileAndDeSerializeToObject(String filename)
			throws IOException, ClassNotFoundException {
		Object object = null;
		System.out.printf("\nDe-serialization bytestream from file: %s", filename);
		try (ObjectInputStream reader = new ObjectInputStream(new FileInputStream(filename))) {
			object = reader.readObject();
		}

		System.out.println(READ_OBJECT + object.toString());

		return object;
	}

	public void serializeObjectAndSaveToFile(Object input) throws FileNotFoundException, IOException {
		String fileName = FILE_NAME_PREFIX + input.getClass().getSimpleName();
		System.out.printf("\nSerialize object: %s \ninto a file: %s\n ", input.toString(), fileName);
		try (ObjectOutputStream writer = new ObjectOutputStream(new FileOutputStream(fileName))) {
			writer.writeObject(input);
		}
	}

}

3.3 Serializable Data Model

A class which implements Serializable interface can save the state of object. The JVM associates a version number to each serializable class to control the class versioning. If a serializable class doesn’t set a serialVersionUID, then JVM generates one automatically based on the class name, data members, and methods. If a class changes its structure, then JVM will re-generate a different serialVersionUID.

It is the best practice to set a serialVersionUID for the serializable class, so the de-serialization process won’t throw java.io.InvalidClassException.

3.3.1 Demo POJO

In this step, I will create a DemoPOJO class which implements Serializable interface and has the following data members:

  • static int count – a static member which will not be serialized
  • static long serialVersionUID – has a default value of 1L. It will be checked during the de-serialization process.
  • String name – will be serialized
  • transient String transientData – will not be serialized.

DemoPOJO.java

package jcg.zheng.demo.serialization.model;

import java.io.Serializable;

public class DemoPOJO implements Serializable {

	public static int count;

	private static final long serialVersionUID = 1L;

	private String name;

//	private String newField;

	private transient String transientData;

	public DemoPOJO() {
		super();
	}

	public String getName() {
		return name;
	}

	public String getTransientData() {
		return transientData;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setTransientData(String transientData) {
		this.transientData = transientData;
	}

	@Override
	public String toString() {
		return "DemoPOJO [name=" + name + ", transientData=" + transientData + "]";
	}

}

3.3.2 Demo NoSerialVersionUID

In this step, I will create a DemoNoSerialVersionUID class which implements Serializable interface and has only one data member:

  • String name – will be serialized

JVM will generate a serialVersionUID and include it in the byte stream generated by the ObjectOutputStream.writeObject. The ObjectInputStream.readObject method will throw java.io.InvalidClassExceptions when the serialVersionUID from the class is different from the byte stream.

DemoNoSerialVersionUID.java

package jcg.zheng.demo.serialization.model;

import java.io.Serializable;

public class DemoNoSerialVersionUID implements Serializable {

	private String name;

//	private String newField;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


	@Override
	public String toString() {
		return "DemoNoSerialVersionUID [name=" + name + "]";
	}

}

3.3.3 Demo AsstHasNoSerVerUID

In this step, I will create a DemoAsstHasNoSerVerUID class which extends from DemoPOJO, implements Serializable interface, and has the following data members:

  • static long serialVersionUID – has a unique value of -5812236843958633933L. It will be used during the de-serialization process.
  • DemoNoSerialVersionUID noSerVerObj – will be serialized. De-serialization process might encounter java.io.InvalidClassException because DemoNoSerialVersionUID does not declare a serialVersionUID.

DemoAsstHasNoSerVerUID.java

package jcg.zheng.demo.serialization.model;

public class DemoAsstHasNoSerVerUID extends DemoPOJO {

	private static final long serialVersionUID = -5812236843958633933L;

//	private String newField;

	private DemoNoSerialVersionUID noSerVerObj;

	public DemoNoSerialVersionUID getNoSerVerObj() {
		return noSerVerObj;
	}

	public void setNoSerVerObj(DemoNoSerialVersionUID noSerVerObj) {
		this.noSerVerObj = noSerVerObj;
	}

	@Override
	public String toString() {
		return "DemoAsstHasNoSerVerUID [noSerVerObj=" + noSerVerObj + ", getName()=" + getName()
				+ ", getTransientData()=" + getTransientData() + "]";
	}

}

4. Demo Application

4.1 DemoApp

In this step, I will create a DemoApp class which serialize and de-serialize the three data model objects.

DemoApp.java

package jcg.zheng.demo.serialization;

import java.io.IOException;

import jcg.zheng.demo.serialization.model.DemoAsstHasNoSerVerUID;
import jcg.zheng.demo.serialization.model.DemoPOJO;
import jcg.zheng.demo.serialization.model.DemoNoSerialVersionUID;

public class DemoApp {

	private static final String TRANSIENT_DATA = "transientData";
	private static final String MARY = "Mary";
	private static final String PREFIX = "ByteStream_";

	public static void main(String[] args) {
		SerializeManager mgr = new SerializeManager();

		DemoApp app = new DemoApp();

		try {

			mgr.serializeObjectAndSaveToFile(app.demoPOJO());

			mgr.readByteStreamFromFileAndDeSerializeToObject(PREFIX + DemoPOJO.class.getSimpleName());

		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {

			mgr.serializeObjectAndSaveToFile(app.demoNoSerialVersionUID());

			mgr.readByteStreamFromFileAndDeSerializeToObject(PREFIX + DemoNoSerialVersionUID.class.getSimpleName());

		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {

			mgr.serializeObjectAndSaveToFile(app.demoAsstHasNoSerVerUID());

			mgr.readByteStreamFromFileAndDeSerializeToObject(PREFIX + DemoAsstHasNoSerVerUID.class.getSimpleName());

		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	private DemoAsstHasNoSerVerUID demoAsstHasNoSerVerUID() {
		DemoAsstHasNoSerVerUID object = new DemoAsstHasNoSerVerUID();
		object.setName(MARY);
		object.setTransientData(TRANSIENT_DATA);

		DemoNoSerialVersionUID noSerVerObj = new DemoNoSerialVersionUID();
		noSerVerObj.setName(MARY);
		object.setNoSerVerObj(noSerVerObj);

		return object;
	}

	private DemoNoSerialVersionUID demoNoSerialVersionUID() {
		DemoNoSerialVersionUID object = new DemoNoSerialVersionUID();
		object.setName(MARY);
		return object;

	}

	private DemoPOJO demoPOJO() {
		DemoPOJO object = new DemoPOJO();
		object.setName(MARY);
		object.setTransientData(TRANSIENT_DATA);

		return object;
	}

}

4.2 Execute First Time

In this step, we execute DemoApp as a Java application. It will first serialize the object into a byte stream, save data to a file. Then it will read the byte stream and de-serialize back to an object. You will see that the transient data member is not serialized.

DempApp output

Serialize object: DemoPOJO [name=Mary, transientData=transientData] 
into a file: ByteStream_DemoPOJO
 
De-serialization bytestream from file: ByteStream_DemoPOJO
to an Object: DemoPOJO [name=Mary, transientData=null]

Serialize object: DemoNoSerialVersionUID [name=Mary] 
into a file: ByteStream_DemoNoSerialVersionUID
 
De-serialization bytestream from file: ByteStream_DemoNoSerialVersionUID
to an Object: DemoNoSerialVersionUID [name=Mary]

Serialize object: DemoAsstHasNoSerVerUID [noSerVerObj=DemoNoSerialVersionUID [name=Mary], getName()=Mary, getTransientData()=transientData] 
into a file: ByteStream_DemoAsstHasNoSerVerUID
 
De-serialization bytestream from file: ByteStream_DemoAsstHasNoSerVerUID
to an Object: DemoAsstHasNoSerVerUID [noSerVerObj=DemoNoSerialVersionUID [name=Mary], getName()=Mary, getTransientData()=null]

4.3 Execute Second Time With Modification

In this step, we will do two steps before execute the DemoApp.

  • uncomment the newField in the three data model classes.
  • comment the serialize steps at line 22, 32, 42 in DemoApp.

As you seen in the output:

  • De-serializing DemoPOJO still works after the class structure changes.
  • De-serialize DemoNoSerialVersionUID failed because the generated serialVersionUID doesn’t match.
  • De-serialize DemoAsstHasNoSerVerUID failed because its object member’s serialVersionUID changes after its structure updated.

DemoApp Output After Modification

De-serialization bytestream from file: ByteStream_DemoPOJO
to an Object: DemoPOJO [name=Mary, transientData=null]

De-serialization bytestream from file: ByteStream_DemoNoSerialVersionUIDjava.io.InvalidClassException: jcg.zheng.demo.serialization.model.DemoNoSerialVersionUID; local class incompatible: stream classdesc serialVersionUID = -4130524204813370227, local class serialVersionUID = 1222651049848203245
	at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
	at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
	at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
	at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
	at jcg.zheng.demo.serialization.SerializeManager.readByteStreamFromFileAndDeSerializeToObject(SerializeManager.java:20)
	at jcg.zheng.demo.serialization.DemoApp.main(DemoApp.java:34)

De-serialization bytestream from file: ByteStream_DemoAsstHasNoSerVerUIDjava.io.InvalidClassException: jcg.zheng.demo.serialization.model.DemoNoSerialVersionUID; local class incompatible: stream classdesc serialVersionUID = -4130524204813370227, local class serialVersionUID = 1222651049848203245
	at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
	at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
	at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
	at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2355)
	at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2249)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2087)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
	at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
	at jcg.zheng.demo.serialization.SerializeManager.readByteStreamFromFileAndDeSerializeToObject(SerializeManager.java:20)
	at jcg.zheng.demo.serialization.DemoApp.main(DemoApp.java:44)

5. Serializable Java Example – Summary

In this example, I demonstrated how Java supports both serialization and de-serialization process with Serializable interface, ObjectInputStream, and ObjectOutputStream classes.

Serialization and de-serialization processes are very useful for transferring the object via network or storing the object into persistent data stores (database, file, and web session).

6. Download the Source Code

Download
You can download the full source code of this example here: Serializable Java Example – How to serialize and deserialize objects

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button