Dig into serialization in Java programming

  • 2020-04-01 04:02:02
  • OfStack

  Java provides a mechanism called serialization, which persists Java objects in an ordered format or sequence of bytes that contains the object's data, the object's type, and the data types stored in the object.

So, if we have serialized an object, it can be read and deserialized by the object's type and other information, and eventually get the prototype of the object.

ObjectInputStream and ObjectOutputStream objects are high-level stream objects that contain methods for serialization and deserialization.

ObjectOutputStream has a number of methods for serializing objects, the most common being:
 


private void writeObject(ObjectOutputStream os) throws IOException
 {
   
 }

A similar ObjectInputStream provides the following method:
 


 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
   
 }

So where does serialization come in? Serialization is usually used when data needs to be transferred over the network, or when objects need to be saved to a file. The data is an object, not a text.

The problem is that both our network architecture and our hard drive recognize only binary and bytes, not Java objects.

Serialization is the translation of the value/states in a Java object into bytes for transmission or storage over the network. In addition, deserialization is done by reading the bytecode and translating it back into a Java object.

SerialVersionUID concept

The serialVersionUID is used to ensure that the same object (which is used in serialization) can be loaded during Deserialization. SerialVersionUID is for versioning objects. You can refer to serialVersionUID in Java serialization for more information.

For serialization:

The steps are as follows:

Let's take a look at one example:

In the SRC - > Org. Arpit. Javapostsforlearning create Employee. Java

1. The Employee. Java 
 


package org.arpit.javapostsforlearning;
import java.io.Serializable;
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
  
 public int getEmployeeId() {
  return employeeId;
 }
 public void setEmployeeId(int employeeId) {
  this.employeeId = employeeId;
 }
 public String getEmployeeName() {
  return employeeName;
 }
 public void setEmployeeName(String employeeName) {
  this.employeeName = employeeName;
 }
 public String getDepartment() {
  return department;
 }
 public void setDepartment(String department) {
  this.department = department;
 }
}

As you can see, if you need to serialize any class, you must implement the Serializable interface, which is the marker interface.


A marker interface in Java is an interface without any fields or methods. To put it simply, an empty interface in Java is called a marker interface.

2. SerializeMain. Java
 


package org.arpit.javapostsforlearning;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 public class SerializeMain {
 
 
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 }
}

For deserialization:
Step is

In the package SRC - > Org. Arpit. Javapostsforlearning, create DeserializeMain. Java
3. DeserializeMain. Java
 


package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
 
public class DeserializeMain {
 
 public static void main(String[] args) {
 
 Employee emp = null;
  try
  {
   FileInputStream fileIn =new FileInputStream("employee.ser");
   ObjectInputStream in = new ObjectInputStream(fileIn);
   emp = (Employee) in.readObject();
   in.close();
   fileIn.close();
  }catch(IOException i)
  {
   i.printStackTrace();
   return;
  }catch(ClassNotFoundException c)
  {
   System.out.println("Employee class not found");
   c.printStackTrace();
   return;
  }
  System.out.println("Deserialized Employee...");
  System.out.println("Emp id: " + emp.getEmployeeId());
  System.out.println("Name: " + emp.getEmployeeName());
  System.out.println("Department: " + emp.getDepartment());
 }
}


4. Run:
First run SerializeMain. Java, then run DeserializeMain. Java, you will get the following results:
 


Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS

So we serialized an employee object and deserialized it. This may seem simple, but if it contains object references, inheritance, then the situation becomes more complicated. Let's take a look at one example after another to see how serialization can be implemented in various situations.

Case 1 - what if the object references another object

Now that we've seen the simplest example of serialization, let's look at how to handle situations where other objects are referenced in an object. How do we serialize? Will reference objects also be serialized? Right, you don't need to serialize the reference object explicitly. When you serialize any object, if it contains a reference object, the Java serialization automatically serializes the entire object graph of that object. For example, Employee now references an address object, and the address references other objects (for example, Home), so when you serialize the Employee object, all other reference objects, such as address and Home, will be automatically serialized. Let's create the Address class and add its Address object as a reference to the employee class.

The Employee. Java:  
 


package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
}

In the org. Arpit. Javapostsforlearning package, create Address. Java
Address. Java:  
 


package org.arpit.javapostsforlearning;
public class Address {
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

In the package org. Arpit. Javapostsforlearning, create SerializeDeserializeMain. Java
SerializeDeserializeMain. Java:
 


package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}

Run it:
When you run SerializeDeserializeMain. Java. You get something like this:
 


java.io.NotSerializableException: org.arpit.javapostsforlearning.Address
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
 at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
 at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.writeObject(Unknown Source) 

We'll explain what went wrong. I forgot to say that the Address class must also be serializable. Then the Address class must inherit the serialzable interface.

Address. Java:
 


import java.io.Serializable;
 
public class Address implements Serializable{
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

Run again:
When you run again SerializeDeserializeMain. Java. You can get the following results
 


Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune

Case 2: if we cannot access the source code of the referenced object (for example, you cannot access the source code of the Address class above)

If we cannot access the address class, how do we implement the serializable interface in the address class? Is there another way to do this? Yes, you can create another class, inherit from Address, and then have it inherit from the serializable interface, but this scheme will fail if:

      If the reference class is defined as final
      If the reference class references another non-serializable object

So, how do we serialize the Employee object? The solution is to mark transient. If you don't need to serialize any fields, just mark it transient.
 
Transient Address Address
In the Employee class, run the program after the address is marked as transient. You will get a nullPointerException because the Address reference will be null during deserialization.


Case 3 - what if I still need to save the state of the reference object? (for example, the address object)

If you mark address as transient during deserialization, it will return null. But if you still need to save its state, you need to serialize the address object. Java serialization provides a mechanism that if you have private methods with a specific signature, they will be called during serialization and deserialization, so we will override the writeObject and readObject methods of the Employee class, and then they will be called during the Employee object serialization/deserialization.

The Employee. Java:


package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 transient Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
 
 private void writeObject(ObjectOutputStream os) throws IOException, ClassNotFoundException
 {
 try {
 os.defaultWriteObject();
 os.writeInt(address.getHomeNo());
 os.writeObject(address.getStreet());
 os.writeObject(address.getCity());
 }
 catch (Exception e)
 { e.printStackTrace(); }
 }
 
 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
 try {
 is.defaultReadObject();
 int homeNo=is.readInt();
 String street=(String) is.readObject();
 String city=(String) is.readObject();
 address=new Address(homeNo,street,city);
 
 } catch (Exception e) { e.printStackTrace(); }
 }
}

Another thing to keep in mind is that the ObjectInputStream reads the data in the same order as the ObjectOutputStream writes the data.

In the package org. Arpit. Javapostsforlearning created in the Address. Java
Address. Java:  
 


package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Address {
 
 int homeNo;
 String street;
 String city;
 
 
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}

In the package org. Arpit. Creating SerializeDeserializeMain javapostsforlearning. Java
SerializeDeserializeMain. Java:
 


package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}

Run:
When you run SerializeDeserializeMain. Java. You will get the following results:  
 


Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune

Now we have the state of the address object, just as it was before it was serialized.

Inheritance in serialization:

Now let's look at how inheritance affects serialization. Whether the parent class is serializable or not, this leads to many examples. If the parent class is not serializable, how do we handle it, and how does it work. Let's look at an example.

We will create a person.java as the parent of Employee.

Case 4: if the parent class is serializable

If the parent class is serializable, then all inherited classes will be serializable.

Case 5: what if the parent class is non-serializable?

If the parent class were non-serializable, we would do things very differently.

      If the parent class is non-serializable, it must not have an argument constructor.

Person. Java 
 


package org.arpit.javapostsforlearning;
public class Person {
 
 String name="default";
 String nationality;
 
 public Person()
 {
 System.out.println("Person:Constructor");
 }
 
 public Person(String name, String nationality) {
 super();
 this.name = name;
 this.nationality = nationality;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 public String getNationality() {
 return nationality;
 }
 
 public void setNationality(String nationality) {
 this.nationality = nationality;
 }
 
}

In the package org. Arpit. Creating the Employee javapostsforlearning. Java
The Employee. Java:

 


package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee extends Person implements Serializable{
 
 int employeeId;
 String department;
 
 public Employee(int employeeId,String name,String department,String nationality)
 {
 super(name,nationality);
 this.employeeId=employeeId;
 this.department=department;
 System.out.println("Employee:Constructor");
 }
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
}

In the org. Arpit. Creating SerializeDeserializeMain javapostsforlearning package. Java

SerializeDeserializeMain. Java:



package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 
 
 public static void main(String[] args) {
 
 //Serialize
 Employee emp = new Employee(101,"Arpit","CS","Indian");
 System.out.println("Before serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 System.out.println("************");
 System.out.println("Serializing");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 System.out.println("************");
 System.out.println("Deserializing");
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("After serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 }
}

Run:

When you run SerializeDeserializeMain. Java, you will get the following output, if the parent class is serializable, so during deserialization, all inherited from the parent class instance variable values, will be by calling the serialization constructors to initialize. Here the name is inherited from the person, so in the deserialization process, the name will be initialized to the default value.


Case 6 - if the parent class is serializable, you do not need to inherit the class to be serializable

If you don't want the inheritance class to be serializable, you'll need to implement the writeObject() and readObject() methods, and you'll need to throw a NotSerializableException.

Case 7 - can a static variable be serialized?

Can't. Because static variables are class level, not object level, when you serialize an object, you cannot serialize static variables.


Conclusion:

      Serialization is the process of converting the values/states of a Java object into bytes and transferring or saving it over a network. In addition, deserialization is the process of translating bytecode into corresponding objects.       The benefit of serialization is that the JVM is independent, meaning that an object can be serialized on one platform and then deserialized on a different platform.       If you want to serialize any object, you must implement the tag interface Serializable.       A Marker interface in Java is an interface without a field or method, or, more simply, an empty interface       The serialVersionUID is used to ensure that the same object (which is used in serialization) can be loaded during Deserialization. SerialVersionUID is for versioning objects.       When you need to serialize any object that contains a reference object, Java automatically serializes the entire object graph for that object.       If you don't want to serialize a field, you can tag it as trasient       If the parent class is serializable, its inheritance classes will also be serializable.       If the parent class is non-serializable, then during deserialization, all the instance variable values inherited from the parent class are initialized by calling the non-serializable constructor.       If you want to subclass serializable, you need to implement the writeObject() and readObject() methods, and throw a NotSerializableException in both methods       You can't serialize static variables.


Related articles: