What happens if the class definition changes between the serialization and the deserialization process ?
It might cause compatibility issues during deserialization process.
At a broad level below changes can happen in class definition between the process of serialization and deserialization :
1. New fields added - This does not lead to any loss of information during the process of deserialization. The new fields added will hold default values of their data type.
2. Fields removed - There is a certain loss of information in this case. Because the fields that are removed from interface (class in this case), there is no way to access those fields.
Let consider each example.
New fields added in class definition :
In the class Person below, there are two fields name and age. The class implements Serializable interface. Also notice that there is no serialVersionUid defined explicitly which means the jvm will evaluate it using class definition and implicitly add it.
Lets create an object of Person and serialize it to person.ser file.
But before deserializing it, lets change the class definition by adding a new field say 'gender' of type String.
Now deserialize the person.ser file by uncommenting LINE 20 in below code (comment LINE 10). Notice that we get the incompatible serialVersionUid exception. This indicates that the jvm changes the default serialVersionUID with changes in the class definition. ( How JVM evaluates serialVersionUID? )
java.io.InvalidClassException: serialize.Person; local class incompatible: stream classdesc serialVersionUID = -2497583579111876693, local class serialVersionUID = 5759024017125419027
Can we avoid this exception and successfully deserialize the object ? Lets see in the next section.
public class Person implements Serializable{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Person p = new Person("Abhi", 28);
SerializerHelper serHelper = p.new SerializerHelper();
serHelper.serialPerson(p); // LINE 10 - serialize
//serHelper.deserialPerson(); // LINE 20 - deserialize
}
private class SerializerHelper{
public void serialPerson(Person p){
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("person.ser")));){
oos.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
}
public Person deserialPerson(){
Person p = null;
try(ObjectInputStream oos = new ObjectInputStream(new FileInputStream(new File("person.ser")));){
p = (Person)oos.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return p;
}
}
}
The exception occurred because the jvm realized that the class for which object was serialized has changed. It was able to judge that from the mismatch in serialVersionUid.
Lets add the serialVersionUid explicitly in the Person class this time.
public class Person implements Serializable{
// serialVersionUID added explictly
private static final long serialVersionUID = 1L;
String name;
int age;
Follow the same steps :
Create a person Object, serialize it.
Add a new field to the class definition.
Now, without changing the serialVersionUid, deserialize the person.ser file.
Added new field in Person Class without changing the serialVersionUID
public class Person implements Serializable{
// serialVersionUID added explictly
private static final long serialVersionUID = 1L;
String name;
int age;
String gender;
...
public static void main(String[] args) {
Person p = new Person("Abhi", 28);
SerializerHelper serHelper = p.new SerializerHelper();
//serHelper.serialPerson(p);
Person p1 = (Person)serHelper.deserialPerson();
System.out.printf("Deserialized person name=%s, age=%d, gender=%s ",p1.name, p1.age, p1.gender);
}
Output : Deserialized person name=Abhi, age=28, gender=null
The person.ser gets deserialized fine now.
Note that the newly added field 'gender' is having a default value null.
Fields removed from class definition : .... To be contd.
No comments:
Post a Comment