Serialization is the process of converting an object's state (including
its references) to a sequence of bytes, as well as the process of
rebuilding those bytes into a live object at some future time.
Some uses of serailization
- Serializable Interface
- Serialization steps
- readObject and writeObjectMethods
- FAQ
Serialization is used when you want to persist the object. It is also
used by RMI to pass objects between JVMs, either as arguments in a
method invocation from a client to a server or as return values from a
method invocation. In general, serialization is used when we want the
object to exist beyond the lifetime of the JVM.
Here are some uses of serialization
- To persist data for future use.
- To send data to a remote computer using such client/server Java technologies as RMI or socket programming.
- To "flatten" an object into array of bytes in memory.
- To exchange data between applets and servlets.
- To store user session in Web applications.
- To activate/passivate enterprise java beans.
- To send objects between the servers in a cluster.
Java provides Serialization API, a standard mechanism to handle
object serialization.
To persist an object in java, we need to follow following steps.
- the first step is to flatten the
object. For that the respective class should implement
"java.io.Serializable" interface. We don't need to implement
any methods as this interface do not have any methods. This is a marker
interface/tag interface. Marking a class as Serializable indicates the
underlying API that this object can be flattened.
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
public class MyDateObject implements Serializable{
private static final long serialVersionUID = -5315058568373987829L;
private Date date;
public MyDateObject() {
date= Calendar.getInstance().getTime();
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date=date;
}
}
2. Next step is to actually persist the object. To persist an object we need to use node stream to write to file systems or transfer a flattened
object across a network. We can use java.io.ObjectOutputStream class for this. So to write an object you use "writeObject(<<instance>>)"
method of "java.io.ObjectOutputStream" class and to read an object you
use "readObject()" method of "java.io.ObjectOutputStream" class.
Note: "readObject()" can read only serialized object, that means if the class
does not implement "java.io.Serializable" interface, "readObject()"
cannot read that object.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
//Class to persist the time in a flat file time.txt
public class WriteSerializeClass {
public static void main(String [] args) {
String filename = "c://time.txt";
if(args.length > 0){
filename = args[0];
}
MyDateObject time = new MyDateObject();
FileOutputStream fos = null;
ObjectOutputStream out = null;
try{
fos = new FileOutputStream(filename);
out = new ObjectOutputStream(fos);
out.writeObject(time);
out.close();
}catch(IOException ex){
ex.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Calendar;
//Class to read the time from a flat file time.txt
public class ReadSerializeClass {
public static void main(String [] args) {
String filename = "c://time.txt";
if(args.length > 0){
filename = args[0];
}
MyDateObject time = null;
FileInputStream fis = null;
ObjectInputStream in = null;
try{
fis = new FileInputStream(filename);
in = new ObjectInputStream(fis);
time = (MyDateObject)in.readObject();
in.close();
}catch(IOException ex){
ex.printStackTrace();
}catch(ClassNotFoundException cnfe){
cnfe.printStackTrace();
}
// print out restored time
System.out.println("Restored time: " + time.getDate());
// print out the current time
System.out.println("Current time: "
+ Calendar.getInstance().getTime());
}
}
readObject and writeObject methods:
To enhance the normal process of serialization/de-serialization provide two methods inside your serializable class. Those methods are:
- private void writeObject(ObjectOutputStream out) throws IOException;
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
Let's look at one example
Without readObjet()/writeObject()
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
public class MyDateObject implements Serializable{
private static final long serialVersionUID = -5315058568373987829L;
private Date date;
public MyDateObject() {
//date= Calendar.getInstance().getTime();
calculateCurrentTime();
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date=date;
}
private void calculateCurrentTime(){
date = Calendar.getInstance().getTime();
}
}
Output:
=================================================================
Restored time: Wed May 28 15:54:31 IST 2014
Current time: Wed May 28 15:54:34 IST 2014
Now we will add the two methods: readObjet()/writeObject()
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
public class MyDateObject implements Serializable{
private static final long serialVersionUID = -5315058568373987829L;
private Date date;
public MyDateObject() {
//date= Calendar.getInstance().getTime();
calculateCurrentTime();
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date=date;
}
private void calculateCurrentTime(){
date = Calendar.getInstance().getTime();
} //Adding writObject()
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
} //Adding readObject()
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException{
in.defaultReadObject();
// now perfrom same operation you need to do in constructor
calculateCurrentTime();
}
}
Output:
=========================================================================
Restored time: Wed May 28 16:08:26 IST 2014
Current time: Wed May 28 16:08:26 IST 2014
So by overriding these two methods, we can easily get desired serialization/de-serialization behavior.
Note: serialization does not care about access modifiers. It serializes all private, public and protected fields.
Again there is one more way to serialize the object - create your own
protocol with the Externalizable interface. Instead of implementing the
Serializable interface, you can implement Externalizable, which contains
two methods:
-
public void writeExternal(ObjectOutput out) throws IOException;
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
The Externalization is discussed as separate post. Check it out here .
Some FAQ:
- why readObject And writeObject declared as private?
Ans: We don't want these methods to be overridden by subclasses. Instead, each class can have its own
writeObject
method, and the serialization engine will call all of them one after
the other. This is only possible with private methods (these are not
overridden). (The same is valid for
readObject
.)
That's why both methods are declared private . The trick here is that the virtual machine
will automatically check to see if either method is declared during the
corresponding method call. The virtual machine can call private methods
of your class whenever it wants but no other objects can. Thus, the
integrity of the class is maintained and the serialization protocol can
continue to work as normal.
2.
How stop from serailizing one of the sub class of a serializable class?
Ans:To stop the automatic serialization, we can once again override the readObject/writeObject
methods to just throw the NotSerializableException in our class.
private void writeObject(ObjectOutputStream out) throws IOException{
throw new NotSerializableException("Dont Serialize");
}
private void readObject(ObjectInputStream in) throws IOException{
throw new NotSerializableException("Dont Serialize");
}
No comments :
Post a Comment