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:
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
Serializableclass with or without aserialVersionUID. - 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)– invokesObjectOutputStream.writeObjectto 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 withObjectInputStream.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 serializedstatic long serialVersionUID– has a default value of1L. It will be checked during the de-serialization process.String name– will be serializedtransient 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 encounterjava.io.InvalidClassExceptionbecauseDemoNoSerialVersionUIDdoes not declare aserialVersionUID.
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
newFieldin the three data model classes. - comment the serialize steps at line 22, 32, 42 in
DemoApp.
As you seen in the output:
- De-serializing
DemoPOJOstill works after the class structure changes. - De-serialize
DemoNoSerialVersionUIDfailed because the generatedserialVersionUIDdoesn’t match. - De-serialize
DemoAsstHasNoSerVerUIDfailed because its object member’sserialVersionUIDchanges 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
You can download the full source code of this example here: Serializable Java Example – How to serialize and deserialize objects


