In Java, serialVersionUID
is something like version control, assure both serialized and deserialized objects are using the compatible class.
For example, if an object saved into a file (Serialization) with serialVersionUID=1L
, when we convert the file back to an object (Derialization), we must use the same serialVersionUID=1L
, otherwise an InvalidClassException
is thrown.
Exception in thread "main" java.io.InvalidClassException: com.favtuts.io.object.Address;
local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
1. POJO
Review a simple Address
class, implements Serializable
, and declared a serialVersionUID = 1L
.
Address.java
package com.favtuts.io.object; import java.io.Serializable; public class Address implements Serializable { private static final long serialVersionUID = 1L; String street; String country; public Address(String street, String country) { this.street = street; this.country = country; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Override public String toString() { return "Address{" + "street='" + street + '\'' + ", country='" + country + '\'' + '}'; } }
2. Test SerialVersionUID.
2.1 Save an object into a file, and convert it back from the file to an object.
ObjectUtils.java
package com.favtuts.io.object; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectUtils { public static void main(String[] args) throws IOException, ClassNotFoundException { Address address = new Address("abc", "Malaysia"); // object -> file try (FileOutputStream fos = new FileOutputStream("address.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(address); oos.flush(); } Address result = null; // file -> object try (FileInputStream fis = new FileInputStream("address.obj"); ObjectInputStream ois = new ObjectInputStream(fis)) { result = (Address) ois.readObject(); } System.out.println(result); } }
Output
Address{street='abc', country='Malaysia'}
2.2 Update the serialVersionUID
to 99L
.
Address.java
public class Address implements Serializable { private static final long serialVersionUID = 99L; String street; String country; //...
Rerun the deserialization process.
Address result = null; // file -> object try (FileInputStream fis = new FileInputStream("address.obj"); ObjectInputStream ois = new ObjectInputStream(fis)) { result = (Address) ois.readObject(); } System.out.println(result);
Now, we hit InvalidClassException
.
xception in thread "main" java.io.InvalidClassException: com.favtuts.io.object.Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 99
at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2014)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1864)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2195)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1681)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:493)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:451)
at com.favtuts.io.object.ObjectUtils.main(ObjectUtils.java:25)
3. When should I update the serialVersionUID?
When we modify a class that will break the compatibility with the existing serialized object, for example, we update the current Address
class, with some fields added and removed.
This new changed will failed all the existing serialized objects, then we should update the serialVersionUID
.
Address.java
public class Address implements Serializable { private static final long serialVersionUID = 9999L; String line1; String line2; Country country; //String street; //String country; }
4. Default serialVersionUID?
If no serialVersionUID
is declared, JVM will use its algorithm to generate a default SerialVersionUID
, check the algorithm here. The default serialVersionUID
computation is highly sensitive to class details and may vary from different JVM implementation, and result in an unexpected InvalidClassExceptions
during the deserialization process.
Review the following example:
Client / Server environment
– The client is using OpenJDK on Windows.
– The server is using GraalVM On Linux.
The client sends the serialized class with SerialVersionUID=1L
to the server. The server may deserialize the class with a different serialVersionUID=99L
, and throws InvalidClassExceptions
. Since both are using different JVM implementation, it might generate a different SerialVersionUID
on both sites.
There are many JVM implementation
Download Source Code
$ git clone https://github.com/favtuts/java-core-tutorials-examples
$ cd java-io/object