Sunday 1 July 2012

Limitations of externalization


Serialization is the process of saving an object state in a storage medium (such as a file, or a memory buffer) or to transmit it over a network connection in binary form.The object can be restored (Deserialization) at a later time, and even a later location. With persistence, we can move an object from one computer to another, and have it maintain its state.

Serialization can be achieved by an object by implementing Serializable interface or Externalizable interface.

The default serialization mechanism by implemeting Serializable interface, here you dont have to do much,just implement Seralizable marker interface in your class and invoke readObject and writeObject methods of DataInputStream and DataOutputStream for seralization and deserialization.

Unlike Serializable interface, Externalizable interface is not a marker interface and it provides two methods - writeExternal and readExternal. These methods are implemented by the class to give the class a complete control over the format and contents of the stream for an object and its supertypes. 


The externalization has its own limitations also.

  • In the default serialization mechanism using Serializable interface,it will implicitly take care of the state of serializable super classes.But in the externalization, the readExternal and writeExternal methods of the class must explicitly coordinate with the supertype to save its state.Example is given below.
  • Whenever there is modification in the class definition you have to explicitly modify your readExternal and writeExternal methods to reflect that changes in the serialization process.But in the default serialization mechanism using Serializable interface the serialization run-time will take care it implicitly.
  • To externalize an object, you need a default public constructor. Externalizable interface can't be implemented by Inner Classes in Java because inner classes can't have a no-arg public constructor.Hence Inner classes can achieve object serialization by only implementing Serializable interface.

Example: An Externalizable class extends a non externalizable super class


Then in this case, you need to persist the super class fields also in the sub class that implements Externalizable interface. Look at this example.

package extern;

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class ExternalizationExample {

 /**
  * @param args
  * @throws ClassNotFoundException
  **/
 public static void main(String[] args) throws ClassNotFoundException {

  ObjectOutputStream out = null;
  ObjectInputStream in = null;
  try {
   out = new ObjectOutputStream(new FileOutputStream("employee.ser"));

   /** Create one Employee object to serialise **/

   Employee emp = new Employee("John", 12345, "Banking");

   /** Serialise the object emp and write to file employee.ser **/

   out.writeObject(emp);

   in = new ObjectInputStream(new FileInputStream("employee.ser"));

   /** Deserialise the object stored in the file employee.ver **/

   Employee emp_copy = (Employee) in.readObject();

   System.out.println(emp_copy);

  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   try {
    out.close();
    in.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

}

class Person {

 String empName;

 public Person() {

 }

 public Person(String empName) {
  this.empName = empName;
 }

 /** Override the toString method to print object fields **/

 public String toString() {
  return ("Employee Name =" + empName);
 }
}

class Employee extends Person implements Externalizable {

 int empno;
 String dept;

 public Employee(String empName, int empno, String dept) {
  super(empName);
  this.empno = empno;
  this.dept = dept;
 }

 /**
  * mandatory public non-arg constructor. It will be invoked during
  * deserialization process.
  **/

 public Employee() {

 }

 /** Override the toString method to print object fields **/

 public String toString() {
  return ("Employee Name =" + empName + " & Employee No =" + empno
    + " &Department =" + dept);
 }

 /** mandatory method.overridden to restore the object state from stream **/
 @Override
 public void readExternal(ObjectInput in) throws IOException,
 ClassNotFoundException {

  // explicitly do the restoring for super class field.
  empName = in.readUTF();

  // Now the sub class fields.
  empno = in.readInt();
  dept = in.readUTF();

 }

 /** mandatory method.overridden to save the object state to stream **/
 @Override
 public void writeExternal(ObjectOutput out) throws IOException {

  // explicitly do the saving for super class field.
  out.writeUTF(empName);

  // Now the sub class fields.
  out.writeInt(empno);
  out.writeUTF(dept);
 }
}

The output will be

Employee Name =John & Employee No =12345 &Department =Banking

Here the Person class does not implement Externalizable interface. So to persist the fields in the Person class the writeExternal and readExternal methods of Employee class are modified to save/restore the super class fields first and then the sub class fields.

If the super class implements the Externalizable interface then super class have its own readExternal and writeExternal methods,  just call the super class readExternal and writeExternal methods from readExternal and writeExternal methods respectively of the sub class.i.e.

Sub class readExternal method.

public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {

super.readExternal(in);
//Now do the restore of sub class fields.
}
Sub class writeExternal method.

public void writeExternal(ObjectOutput out) throws IOException {

super.writeExternal(out);
//do the saving of sub class fields.
}

No comments:

Post a Comment