Java serialization when object changed 2016-12-01 07:45
It is easy to serialize object to byte array and deserialize byte array to object. Today I will show you how to serialize and deserialize object when it changed.
1. Preparation
The pom file is like following.
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
The first version of User
class is like following.
public class User implements Serializable {
private static final long serialVersionUID = -6704164414515767927L;
private String name;
private String address;
private String age;
//getter and setter methods
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age='" + age + '\'' +
'}';
}
}
Serialize object to byte array and save it into file.
public class TestSerialize {
public static void main(String[] args) throws IOException {
User user = new User();
user.setName("henry");
user.setAddress("beijing");
user.setAge("27");
FileUtils.writeByteArrayToFile(new File("/user_version1.txt"), SerializationUtils.serialize(user));
}
}
2. Change fields of User
class
Add test
field and delete age field.
public class User implements Serializable {
private static final long serialVersionUID = -6704164414515767927L;
private String name;
private String address;
private String test;
//getter and setter methods
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", test='" + test + '\'' +
'}';
}
}
Read byte array from "user_version1.txt" and deserialize to new version of User
.
public class TestDeserialize {
public static void main(String[] args) throws IOException {
Path path = Paths.get("/user_version1.txt");
byte[] data = Files.readAllBytes(path);
User user = SerializationUtils.deserialize(data);
System.out.println(user);
}
}
The output is like following.
User{name='henry', address='beijing', test='null'}
3. Change the value of serialVersionUID
public class User implements Serializable {
private static final long serialVersionUID = -6L;
private String name;
private String address;
private String age;
//getter and setter methods
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age='" + age + '\'' +
'}';
}
}
Deserialize this object again. We got the Exception like following.
Exception in thread "main" org.apache.commons.lang3.SerializationException: java.io.InvalidClassException: com.henryxi.serialize.User; local class incompatible: stream classdesc serialVersionUID = -6704164414515767927, local class serialVersionUID = -6
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:231)
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:267)
at com.henryxi.serialize.TestDeserialize.main(TestDeserialize.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.io.InvalidClassException: com.henryxi.serialize.User; local class incompatible: stream classdesc serialVersionUID = -6704164414515767927, local class serialVersionUID = -6
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:223)
... 7 more
4. Delete the value of serialVersionUID
public class User implements Serializable {
private String name;
private String address;
private String age;
//getter and setter methods
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age='" + age + '\'' +
'}';
}
}
Deserialize this object again. We got the same Exception.
Exception in thread "main" org.apache.commons.lang3.SerializationException: java.io.InvalidClassException: com.henryxi.serialize.User; local class incompatible: stream classdesc serialVersionUID = -6704164414515767927, local class serialVersionUID = 2510146339395188803
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:231)
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:267)
at com.henryxi.serialize.TestDeserialize.main(TestDeserialize.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.io.InvalidClassException: com.henryxi.serialize.User; local class incompatible: stream classdesc serialVersionUID = -6704164414515767927, local class serialVersionUID = 2510146339395188803
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at org.apache.commons.lang3.SerializationUtils.deserialize(SerializationUtils.java:223)
... 7 more
5. Conclusion
- Deserializing will be success when we only change the field of object. removed field -> lost , new field -> default value.
- Deserializing will be fail when we change
serialVersionUID
. - Deserializing will be fail when we delete
serialVersionUID
.
serialVersionUID
must be defined in the object when you need serialize and deserialize object. If there is no serialVersionUID
or the value of serialVersionUID
changed deserializing will be fail.