Friday, November 10, 2017

Java Object Serialization

Serialization is process of converting state of java object into ByteStream so that it can be sent over the network or can be saved to database or any file.
Serialization is an integral part of Java since 1.1 version. Many times you may want to save the state of an object for later use or want to transfer fully loaded object over the network to some other machine where it can be reconstructed again. Serialization is the solution. Serialization can be achieved by implementing Serializable interface. Serializable interface is a marker interface so you need not to provide any method implementation for that. A basic serializable class may look like this:
public class Student implements Serializable {
private static final long serialVersionUID = -3646265306996988550L;
private String name;
private String school;
private String clazz;
private List<String> subjects;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public List<String> getSubjects() {
return subjects;
}
public void setSubjects(List<String> subjects) {
this.subjects = subjects;
}
}
You can understand it with the help of following diagram.
Ser-de
Let’s suppose you want to serialize object of this class. Java provided ObjectOutputStream class implementation of OutputStream that can be used for writing object to persistence media (File, DB, or Network).
Look at following code snippet:
public class TestSerialization {
public static void main(String[] args) {
Student student = new Student();
student.setName(“Kuldeep”);
student.setSchool(“Cambridge”);
student.setClazz(“MCA”);
List<String> subjects = new ArrayList<>();
subjects.add(“Computer Application”);
subjects.add(“Java”);
subjects.add(“UNIX”);
student.setSubjects(subjects);
System.out.println(“Student: ” + student);
String path = “student.ser”;
serialize(student, path);
}
public static void serialize(Student student, String path) {
try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(path));) {
outputStream.writeObject(student);
} catch (IOException e) {
e.printStackTrace();
}
}
}
In above code notice serialize() method, outputStream.writeObject(student) is actually writing object state to file named “student.ser”. In future same state can be reconstructed using this file on same machine or any other machine.
Process of reconstruction of object state from bytes stream is called DeSerilization.
You don’t need to implement any other interface for reconstructing the object from a serialized object bytes stream. You just need to create ObjectInputStream to read from file (here student.ser) and read object like below.
public static Student deSerialize(String path) {
Student student = null;
try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path))) {
student = (Student) inputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return student;
}
If you notice object returned from readObject() method is downcast to Student. This is because readObject() method always returns object of type Object (Parent class of all objects in JAVA). To get our required object we need to downcast Object to our class. At the time of downcast Student (or any class you want to downcast to) must be available in classpath, otherwise you will face, Student cannot be resolved to a type, error and your code will not compile.
Java comes with many library classes with serializable capability like String, All Collection classes, Wrapper Classes and many more.
Referenced Object Serialization: Your serializable class may have reference of some other classes or extending any class.
Case 1- Student class extending Person: If Student is extending Person class and person is not serializable, Serialization/Deserialization will be performed without any behavior. But that might result in unexpected behavior. If Person class is not serializable, you will not be able to serialize fields in Student inherited from Person. When you will deserialize Student object, all those field will be initialized with default value, doesn’t matter what was the value at the time of serialization. You may want to serialize these fields as well. Confused? Don’t be. Very simple solution to achieve this is, just make Person Serializable (Of course, you can remove “implements Serializable” from Student class, as it will inherit serializable behavior from Person class).

Case 2- Student is holding reference of some other class: Suppose Student class has reference of another class like Address. Address may or may not be serializable. If you are serializing Student and Address is not Serializable you will get an “java.io.NotSerializableException: serialization.Address”. You need to make Address serializable.
Serial Version UID: For every Serializable class there is one mandatory field “serialVersionUID”. You may or may not provide it in your class like
private static final long serialVersionUID = -8560840887092053121L;
If serialVersionUID is not provided explicitly, JVM will generate one for you. It is generated with the help of different components of class like class name, implemented interfaces, public protected members etc.
There are some issues with default serialVersionUID. It’s very sensitive to the class details. And it might be possible different JVM generates different serialVersionUID for same class. So, it’s always a good idea to provide a serialVersionUID yourself. You can generate serialVersionUID either with the help of  eclipse IDE or serialver tool available in JDK.
You can also provide any default value for serialVersionUID like
private static final long serialVersionUID = 1L;
This is not preferred way, because it will always remain same and any change to the class will not be reflected in serialVersionUID. So, always go with generated serialVersionUID as it is a best practice.
Transient keyword: If you want any member variable of your class not to be serialized, transient rescue you. transient is java reserved keyword that can be used with class variables. Take example of Person class below.
public class Person implements Serializable {
private static final long serialVersionUID = 1346844947009753416L;
protected String name;
transient protected int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here age is marked as transient, so when you serialized Person class, age’s value will not be persisted and deserialization will initialize it with its default value.
I hope this article will help you to understand basics of Serialization process in Java.
We will discuss about controlled Serialization called Externalization in my next article.
Happy learning!
Your input, suggestions or questions are always welcome.

0 comments:

Post a Comment