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
Serializable
class 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.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 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.InvalidClassException
becauseDemoNoSerialVersionUID
does 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
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 generatedserialVersionUID
doesn’t match. - De-serialize
DemoAsstHasNoSerVerUID
failed because its object member’sserialVersionUID
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
You can download the full source code of this example here: Serializable Java Example – How to serialize and deserialize objects