Tuesday, January 14, 2014

Externalization in Java


In my previous post ( Serialization), we saw about Serialization. While using Serialization we can get some limitations.

Limitations of Serialization:
  1. File size is very high because it contains meta information of the file.
  2. Customization due to transient which is not effective because we get “null” in place of transient attributes.
To overcome the limitations of Serialization, we can use the Externalization.

Externalization(java.io.Externalizable): 

Externalization is nothing but serialization but by implementing Externalizable interface to persist and restore the object. To make our object as externalize we need to implement with Externalizable interface.

Unlike Serializable interface, it is not a marker interface which contains two methods 

public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

In Serialization process, JVM has full control for serializing object but in Externalization process application/developer gets control for persisting objects. In Externalization process, writeExternal() and readExternal() method provides complete control on format and content of Serialization process.

In writeExternal() method we are making attributes as externalized by using corresponding methods for different types of data.

writeInt()    --> for Integer
writeLong() --> for Long
writeDouble() --> for Double
writeUTF()    --> for String (UTF --> Universal Text Format)
writeObject() --> for Derived attributes other than String & Wrapper classes etc..

In the same way, readExternal() method also provides some methods. By using those methods we can get the externilized attributes.

readInt();
readLong();
readDouble();
readUTF();
readObject();

Employee.java

package com.ranga;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

/**
 * Created by ranga on 1/12/14.
 */

public class Employee implements Externalizable {
  private long serialVersionUID = 31462223600l;

  private long id;
  private String firstName;
  private String lastName;
  private int age;
  private String address;

  public Employee() {
    super();
  }

  public Employee(long id, String firstName, String lastName, int age, String address) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.address = address;
  }
  public Employee(int age) {
    this.age = age;
  }

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getAddress() {
    return address;
  }

  public void setAddress(String address) {
    this.address = address;
  }

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeLong(id);
    out.writeUTF(firstName);
    out.writeUTF(lastName);
    out.writeInt(age);
    out.writeUTF(address);
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    id = in.readLong();
    firstName = in.readUTF();
    lastName = in.readUTF();
    age = in.readInt();
    address = in.readUTF();
  }

  @Override
  public String toString() {
    return "Employee{" +
        "id=" + id +
        ", firstName='" + firstName + '\'' +
        ", lastName='" + lastName + '\'' +
        ", age=" + age +
        ", address='" + address + '\'' +
        '}';
  }

}

ExternalizationDemo.java

package com.ranga;

import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/**
 * Created by ranga on 1/13/14.
 */

public class ExternalizationDemo {
  public static void main(String[] args) {
    Employee employee = new Employee();
    employee.setId(143);
    employee.setFirstName("Ranga");
    employee.setLastName("Reddy");
    employee.setAge(25);
    employee.setAddress("MPL, Chittoor, AP");

    FileOutputStream fileOutputStream = null;
    ObjectOutputStream objectOutputStream = null;

    try {
      fileOutputStream = new FileOutputStream( new File("employees.ser"));
      objectOutputStream = new ObjectOutputStream(fileOutputStream);
      objectOutputStream.writeObject(employee);
      System.out.println("Employee Object Externalization Done Successfully.");
    } catch(Exception ex) {
      ex.printStackTrace();
    } finally {
      if(objectOutputStream != null) {
        try {
          objectOutputStream.close();
        } catch(Exception ex) {
          ex.printStackTrace();
        }
      }
      if(fileOutputStream != null) {
        try {
          fileOutputStream.close();
        } catch(Exception ex) {
          ex.printStackTrace();
        }
      }
    }
  }
}

Output:
Employee Object Externalization Done Successfully.

DeExternalizationDemo.java

package com.ranga;

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;

/**
 * Created by ranga on 1/13/14.
 */
public class DeExternalizationDemo {
  public static void main(String[] args) {
    FileInputStream fileInputStream = null;
    ObjectInputStream objectInputStream = null;

    try {
      fileInputStream = new FileInputStream(new File("employees.ser"));
      objectInputStream = new ObjectInputStream(fileInputStream);
      Employee employee = (Employee) objectInputStream.readObject();
      System.out.println("Employee Info: "+employee);
    } catch(Exception ex) {
      ex.printStackTrace();
    } finally {
      if(objectInputStream != null) {
        try {
          objectInputStream.close();
        } catch(Exception ex) {
          ex.printStackTrace();
        }
      }
      if(fileInputStream != null) {
        try {
          fileInputStream.close();
        } catch(Exception ex) {
          ex.printStackTrace();
        }
      }
    }
  }
}

Output:
Employee Info: Employee{id=143, firstName='Ranga', lastName='Reddy', age=25, address='MPL, Chittoor, AP'}

Only those fields will be persisted as byte stream that will be saved by writeExternal and readExternal. Other field in the class will not be externalized. So by Externalizable interface java developer has complete control on java class persistence.

Externalizable provides complete control, it also presents challenges to serialize super type state and take care of default values in case of transient variable and static variables in Java. If used correctly Externalizable interface can improve performance of serialization process.

Advantages:

The main advantages of externalization over serialization are:
1)File size is highly reduced(nearly 1/3)
2) Customization is very easy and more effective.

Performance issue:
 
1. Further more if you are subclassing your externalizable class you will want to invoke your superclass’s implementation. So this causes overhead while you subclass your externalizable class.
2. methods in externalizable interface are public. So any malicious program can invoke which results into lossing the prior serialized state.


Difference between Serialization and Externalization:

1. With the classes which implement Serializable, the serialization of the object is taken care of automatically, while classes that implement Externalizable is responsible for serializing itself, without the help of default serialization procedures.
2. when we serialize an Externalizable object, a default constructor will be called automatically after that will the readExternal() method be called.

1 comments:

Unknown said...

You can generate java value objects that implement Externalizable for you without having to write the code yourself using VALJOGen (http://valjogen.41concepts.com/).