Wednesday, September 28, 2011

Java Serialization

In this section, you will learn how to serialize and deserialize  an object with the example code.
In Java, Object can be represented as sequence of byte which have data as well as information about states of object. Information about states of objects includes type of object and the data types stored in the object. Representing object into this form is known asObject Serialization.
And the recreation of object into the memory from this sequence of byte, is known as Deserialization.
Serialized object can be write into a file or can also store into data base.
Serialization & deserialization is independent of JVM. It means an object can be serialized on one platform and can also recreate or deserialized on a totally dissimilar platform.
The ObjectOutputStream  class is used to serialize a object and also contained methods associated with Serialization.
The ObjectInputStream class is used to deserialize a object and also contained methods associated with Deserialization.

Serializing a class

For serializing a class successfully, following things must be keep in mind :
  • The class must implements the java.io.Serializable interface.
  • If you want to avoid serialization of any field or any field is not serializable(Ex. Thread field), it must be declared using transient keyword as follows :
     public int transient secondaryMobile;
          Due to the above declaration secondaryMobile field will be ignored during serialization.

EXAMPLE 1: Serializing an object & storing it into a file

In the given below example, we are going to serialize a class Student and storing it into a file named as "student.ser".
Note :By Java convention, when we Serializing an object to a file, it must have extension .ser. For Example : student.ser
We are going to serialize the below class Student, it must implements java.io.Serializable interface :
public class Student implements java.io.Serializable{
public String name;
public String address;
public transient int rollno;
public int roomNo;
}
The ObjectOutputStream class is used to serialize an Object. The following SerializeExample program instantiates an Student object and serializes it to a file.
When the below code executed successfully, it will produce a file student.ser and gives output messageGiven below the code of SerializeExample  class :
import java.io.*;
public class SerializeExample {
public static void main(String[] args) {
Student e = new Student();
e.name = "Kapil k Singh";
e.address = "E-247,Beta-1,Noida";
e.rollno = 513210153;
e.roomNo = 111;
try {
FileOutputStream fileOut = new FileOutputStream("student.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.println("Object is serialized & stored in 'student.ser'");
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
It will produce the following output :
Object is serialized & stored in 'student.ser'              

EXAMPLE 2: Deserializing an Object:

Given below code will deserialize the student object created in the above(SerializeExample) code :
import java.io.*;
public class DeserializeExample {
public static void main(String[] args) {
Student e = null;
try {
FileInputStream fileIn = new FileInputStream("Student.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Student) in.readObject();
in.close();
fileIn.close();
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("Student class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Student...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("Roll no: " + e.rollno);
System.out.println("Room No: " + e.roomNo);
}
}
The above code will produce the following output :
Deserialized Student...
Name: Kapil k Singh
Address: E-247,Beta-1,Noida                           
Roll no: 0
Room No: 111
In the above output, you can see that the Roll number field is showing 0 instead of 513210153. This is because, we set it transient. Due to this, it is not serialized and it will give default value 0(zero). In case of string it is null.



import java.io.*;
public class SerializationDemo {
public static void main(String args[]) {
// Object serialization
try {
MyClass object1 = new MyClass("Hello", -7, 2.7e10);
System.out.println("object1: " + object1);
FileOutputStream fos = new FileOutputStream("serial");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
oos.flush();
oos.close();
}
catch(Exception e) {
System.out.println("Exception during serialization: " + e);
System.exit(0);
}
// Object deserialization
try {
MyClass object2;
FileInputStream fis = new FileInputStream("serial");
ObjectInputStream ois = new ObjectInputStream(fis);
object2 = (MyClass)ois.readObject();
ois.close();
System.out.println("object2: " + object2);
}
catch(Exception e) {
System.out.println("Exception during deserialization: " +
e);
System.exit(0);
}
}
}
class MyClass implements Serializable {
String s;
int i;
double d;
public MyClass(String s, int i, double d) {
this.s = s;
this.i = i;
this.d = d;
}
public String toString() {
return "s=" + s + "; i=" + i + "; d=" + d;
}
}
This program demonstrates that the instance variables of object1 and object2 are
identical. The output is shown here:
object1: s=Hello; i=-7; d=2.7E10
object2: s=Hello; i=-7; d=2.7E10
Serialization is the process of saving an object in a storage medium (such as a file, or a memory buffer) or to transmit it over a network connection  in binary form.  The serialized objects are JVM independent and can be re-serialized by any JVM. In this case the "in memory" java objects state are converted into a byte stream. This type of the file can not be understood by the user. It is a special types of object i.e. reused by the JVM (Java Virtual Machine). This process of serializing an object is also called deflating or marshalling an object.
The given example shows the implementation of serialization to an object. This program takes a file name that is machine understandable and then serialize the object. The object to be serialized must implement java.io.Serializable class.
Default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields.
class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,
ObjectOutput interface extends the DataOutput interface and adds methods for serializing objects and writing bytes to the file. The ObjectOutputStream extends java.io.OutputStream and  implementsObjectOutput  interface. It serializes objects, arrays, and other values to a stream. Thus theconstructor of  ObjectOutputStream is written as:
ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));
Above code has been used to create the instance of the ObjectOutput class with the ObjectOutputStream( ) constructor which takes the instance of the FileOuputStream as a parameter.
The ObjectOutput interface is used by implementing the ObjectOutputStream class. TheObjectOutputStream is constructed to serialize the object.
writeObject():
Method writeObject() writes an object to the given stream.
Here is the code of program:

import java.io.*;
  public class SerializingObject{
  
  
public static void main(String[] argsthrows IOException{
  BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  System.out.print("Please enter File name : ");
  
  
String file = in.readLine();

 
System.out.print("Enter extention : ");
  
  
String ext = in.readLine();

  
String filename = file + "." + ext;

 
File f = new File(filename);

  
try{

 
ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

 
ObjOut.writeObject(f);

  
 ObjOut.close();

 
System.out.println(
   
"Serializing an Object Creation completed successfully.");
  
  
}
  catch(IOException e){

 
System.out.println(e.getMessage());

    }
  
}


  }



Input and Output Object Streams

ObjectOutputStream is the primary output stream class that implements the ObjectOutput interface for serializing objects. ObjectInputStream is the primary input stream class that implements the ObjectInput interface for deserializing objects.
These high-level streams are each chained to a low-level stream, such as FileInputStream or FileOutputStream.
The low-level streams handle the bytes of data. The writeObject method saves the state of the class by writing the individual fields to the ObjectOutputStream. The readObject method is used to deserialize the object from
the object input stream.
Case 1: Below is an example that demonstrates object Serialization into a File
PersonDetails is the bean class that implements the Serializable interface
import java.io.Serializable;
public class PersonDetails implements Serializable {

	private String name;
	private int age;
	private String sex;
	public PersonDetails(String name, int age, String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	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;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
}
GetPersonDetails is the class that is used to Deserialize object from the File (person.txt).
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
public class GetPersonDetails {

	public static void main(String[] args) {
		String filename = "person.txt";
		List pDetails = null;
		FileInputStream fis = null;
		ObjectInputStream in = null;
		try {
			fis = new FileInputStream(filename);
			in = new ObjectInputStream(fis);
			pDetails = (ArrayList) in.readObject();
			in.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		// print out the size
		System.out.println("Person Details Size: " + pDetails.size());
		System.out.println();
	}
}
PersonPersist is the class that is used to serialize object into the File (person.txt).
public class PersonPersist {

	public static void main(String[] args) {
		String filename = "person.txt";
		PersonDetails person1 = new PersonDetails("hemanth", 10, "Male");
		PersonDetails person2 = new PersonDetails("bob", 12, "Male");
		PersonDetails person3 = new PersonDetails("Richa", 10, "Female");
		List list = new ArrayList();
		list.add(person1);
		list.add(person2);
		list.add(person3);
		FileOutputStream fos = null;
		ObjectOutputStream out = null;
		try {
			fos = new FileOutputStream(filename);
			out = new ObjectOutputStream(fos);
			out.writeObject(list);
			out.close();
			System.out.println("Object Persisted");
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}
——————————————————————————–
Case 2: Below is an example that demonstrates object Serialization into the database
PersonDetails remains the same as shown above
GetPersonDetails remains the same as shown above
Create SerialTest Table
create table SerialTest(
name BLOB,
viewname VARCHAR2(30)
);
PersonPersist is the class that is used to serialize object into the into the Database Table SerialTest.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PersonPersist {

	static String userid = "scott", password = "tiger";
	static String url = "jdbc:odbc:bob";
	static int count = 0;
	static Connection con = null;
	public static void main(String[] args) {
		Connection con = getOracleJDBCConnection();
		PersonDetails person1 = new PersonDetails("hemanth", 10, "Male");
		PersonDetails person2 = new PersonDetails("bob", 12, "Male");
		PersonDetails person3 = new PersonDetails("Richa", 10, "Female");
		PreparedStatement ps;
		try {
			ps = con
					.prepareStatement("INSERT INTO SerialTest VALUES (?, ?)");
			write(person1, ps);
			ps.execute();
			write(person2, ps);
			ps.execute();
			write(person3, ps);
			ps.execute();
			ps.close();
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery("SELECT * FROM SerialTest");
			while (rs.next()) {
				Object obj = read(rs, "Name");
				PersonDetails p = (PersonDetails) obj;
				System.out.println(p.getName() + "\t" + p.getAge() + "\t"
						+ p.getSex());
			}
			rs.close();
			st.close();
		} catch (Exception e) {
		}
	}
	public static void write(Object obj, PreparedStatement ps)
			throws SQLException, IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oout = new ObjectOutputStream(baos);
		oout.writeObject(obj);
		oout.close();
		ps.setBytes(1, baos.toByteArray());
		ps.setInt(2, ++count);
	}
	public static Object read(ResultSet rs, String column)
			throws SQLException, IOException, ClassNotFoundException {
		byte[] buf = rs.getBytes(column);
		if (buf != null) {
			ObjectInputStream objectIn = new ObjectInputStream(
					new ByteArrayInputStream(buf));
			return objectIn.readObject();
		}
		return null;
	}
	public static Connection getOracleJDBCConnection() {
		try {
			Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
		} catch (java.lang.ClassNotFoundException e) {
			System.err.print("ClassNotFoundException: ");
			System.err.println(e.getMessage());
		}
		try {
			con = DriverManager.getConnection(url, userid, password);
		} catch (SQLException ex) {
			System.err.println("SQLException: " + ex.getMessage());
		}
		return con;
	}
}
——————————————————————————–
Case 3: Below is an example that demonstrates object Serialization into the database using Base 64 Encoder
PersonDetails remains the same as shown above
GetPersonDetails remains the same as shown above
Create SerialTest Table
create table SerialTest(
name BLOB,
viewname VARCHAR2(30)
);
PersonPersist is the class that is used to serialize object into the Database Table SerialTest
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PersonPersist {

	static String userid = "scott", password = "tiger";
	static String url = "jdbc:odbc:bob";
	static int count = 0;
	static Connection con = null;
	static String s;
	public static void main(String[] args) {
		Connection con = getOracleJDBCConnection();
		PersonDetails person1 = new PersonDetails("hemanth", 10, "Male");
		PersonDetails person2 = new PersonDetails("bob", 12, "Male");
		PersonDetails person3 = new PersonDetails("Richa", 10, "Female");
		PreparedStatement ps;
		try {
			ps = con
					.prepareStatement("INSERT INTO SerialTest VALUES (?, ?)");
			write(person1, ps);
			ps.execute();
			write(person2, ps);
			ps.execute();
			write(person3, ps);
			ps.execute();
			ps.close();
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery("SELECT * FROM SerialTest");
			while (rs.next()) {
				Object obj = read(rs, "Name");
				PersonDetails p = (PersonDetails) obj;
				System.out.println(p.getName() + "\t" + p.getAge() + "\t"
						+ p.getSex());
			}
			rs.close();
			st.close();
		} catch (Exception e) {
		}
	}
	public static void write(Object obj, PreparedStatement ps)
			throws SQLException, IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oout = new ObjectOutputStream(baos);
		oout.writeObject(obj);
		oout.close();
		byte[] buf = baos.toByteArray();
		s = new sun.misc.BASE64Encoder().encode(buf);
		ps.setString(1, s);
		// ps.setBytes(1, Base64.byteArrayToBase64(baos.toByteArray()));
		ps.setBytes(1, baos.toByteArray());
		ps.setInt(2, ++count);
	}
	public static Object read(ResultSet rs, String column)
			throws SQLException, IOException, ClassNotFoundException {
		byte[] buf = new sun.misc.BASE64Decoder().decodeBuffer(s);
		// byte[] buf = Base64.base64ToByteArray(new
		// String(rs.getBytes(column)));
		if (buf != null) {
			ObjectInputStream objectIn = new ObjectInputStream(
					new ByteArrayInputStream(buf));
			Object obj = objectIn.readObject(); // Contains the object
			PersonDetails p = (PersonDetails) obj;
			System.out.println(p.getName() + "\t" + p.getAge() + "\t"
					+ p.getSex());
		}
		return null;
	}
	public static Connection getOracleJDBCConnection() {
		try {
			Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
		} catch (java.lang.ClassNotFoundException e) {
			System.err.print("ClassNotFoundException: ");
			System.err.println(e.getMessage());
		}
		try {
			con = DriverManager.getConnection(url, userid, password);
		} catch (SQLException ex) {
			System.err.println("SQLException: " + ex.getMessage());
		}
		return con;
	}
}
Below is a program that shows the serialization of a JButton object to a file and a Byte Array Stream. As before theobject to be serialized must implement the Serializable interface.
PersonDetails is the bean class that implements the Serializable interface
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class ObjectSerializationExample {

	public static void main(String args[]) {
		try {
			Object object = new javax.swing.JButton("Submit");
			// Serialize to a file namely "filename.dat"
			ObjectOutput out = new ObjectOutputStream(
					new FileOutputStream("filename.dat"));
			out.writeObject(object);
			out.close();
			// Serialize to a byte array
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			out = new ObjectOutputStream(bos);
			out.writeObject(object);
			out.close();
			// Get the bytes of the serialized object
			byte[] buf = bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}



Difference between Serializable and Externalizable 

To add to the other answers, by implementating java.io.Serializable, you get "automatic" serialization capability for objects of your class. No need to implement any other logic, it'll just work. The Java runtime will use reflection to figure out how to marshal and unmarshal your objects.
In earlier version of Java, reflection was very slow, and so serializaing large object graphs (e.g. in client-server RMI applications) was a bit of a performance problem. To handle this situation, thejava.io.Externalizable interface was provided, which is like java.io.Serializable but with custom-written mechanisms to perform the marshalling and unmarshalling functions (you need to implement readExternal and writeExternal methods on your class). This gives you the means to get around the reflection performance bottleneck.
In recent versions of Java (1.3 onwards, certainly) the performance of reflection is vastly better than it used to be, and so this is much less of a problem. I suspect you'd be hard-pressed to get a meaningful benefit from Externalizable with a modern JVM.
Also, the built-in Java serialization mechanism isn't the only one, you can get third-party replacements, such as JBoss Serialization, which is considerably quicker, and is a drop-in replacement for the default.
A big downside of Externalizable is that you have to maintain this logic yourself - if you add, remove or change a field in your class, you have to change your writeExternal/readExternal methods to account for it.
In summary, Externalizable is a relic of the Java 1.1 days. There's really no need for it any more.
      

 


// : c12:Blip3.java
// Reconstructing an externalizable object.
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.

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 Blip3 implements Externalizable {
  private int i;

  private String s; // No initialization

  public Blip3() {
    System.out.println("Blip3 Constructor");
    // s, i not initialized
  }

  public Blip3(String x, int a) {
    System.out.println("Blip3(String x, int a)");
    s = x;
    i = a;
    // s & i initialized only in nondefault constructor.
  }

  public String toString() {
    return s + i;
  }

  public void writeExternal(ObjectOutput outthrows IOException {
    System.out.println("Blip3.writeExternal");
    // You must do this:
    out.writeObject(s);
    out.writeInt(i);
  }

  public void readExternal(ObjectInput inthrows IOException,
      ClassNotFoundException {
    System.out.println("Blip3.readExternal");
    // You must do this:
    s = (Stringin.readObject();
    i = in.readInt();
  }

  public static void main(String[] argsthrows IOException,
      ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip3 b3 = new Blip3("A String "47);
    System.out.println(b3);
    ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
        "Blip3.out"));
    System.out.println("Saving object:");
    o.writeObject(b3);
    o.close();
    // Now get it back:
    ObjectInputStream in = new ObjectInputStream(new FileInputStream(
        "Blip3.out"));
    System.out.println("Recovering b3:");
    b3 = (Blip3in.readObject();
    System.out.println(b3);
  }
///:~

No comments:

Post a Comment