http://www.developer.com/

Back to article

Java Serialization: Persist Your Objects


February 8, 2010

When a Java application is executed, a large number of objects are created. Most of these objects are created and destroyed in the runtime. It would be convenient if Java saved these objects for future use or recreated them from an existing source and then used them—even when the application is re-run after it was stopped. The good news is Java does support this mechanism with the Java Serialization API.

Serialization is the process of saving an object's state to a persistence store and also rebuilding the object from the saved information when needed in the future. With Serialization, you can serialize (persist) any object that you don't need or that may have been used in some other application or may be used later.

Understanding the Java Serialization API

Any Java object can be a candidate for serialization; it simply needs to implement the Serializable interface. This interface is a marker interface with no default implementation. The interface is an indication to the Java runtime that the object is valid for persistence.

The method writeObject(...) of the ObjectOutputStream class makes the serialization transparent to the developer. You don't need to worry about creating the persistent file, reading the end-of-file, creating a new file, etc., thereby relieving you of a lot of additional effort.

As an example, here is a DataAndTimeObject class that can be serialized:

import java.io.Serializable;
import java.util.*;
 
//This class represents DataAndTimeObject that can be serialized
public class DateAndTimeObject implements Serializable
{
   private Date dateAndTime;
 
   public DateAndTimeObject()
   {
      dateAndTime = Calendar.getInstance().getTime();
   }
 
   public Date getDateAndTime()
   {
      return dateAndTime;
   }
}


The difference between the above object and a non-serializable object is that this one implements the Serializable interface.

The following code shows how you would serialize the object DataAndTimeObject.

import java.io.*;
 
//This class provides methods to serialize a serializable object
public class SerializeObject
{
   public static void main(String args[])
   {
      String serializeFileName = "dateAndTime.ser";
      if(args.length > 0)
      {
         serializeFileName = args[0];
      }
 
      DateAndTimeObject dateAndTimeObject = new DateAndTimeObject();
      FileOutputStream fileOutputStream = null;
      ObjectOutputStream objectOutputStream = null;
 
      try
      {
         fileOutputStream = new FileOutputStream(serializeFileName);
         objectOutputStream = new ObjectOutputStream(fileOutputStream);
         //The object is being persisted here
         objectOutputStream.writeObject(dateAndTimeObject);
         objectOutputStream.close();
         System.out.println("Serialize Date and Time   : " + dateAndTimeObject.getDateAndTime());
         System.out.println("Object serialized in file : " + serializeFileName);
      }
      catch(IOException ioe)
      {
         //Close all I/O streams
         ioe.printStackTrace();
         //Handle the exception here
      }
   }
}


Here is the output from the above code.

The class SerializeObject has an implementation that can serialize the object DataAndTimeObject. This implementation also takes an argument for the serialize object file name, ignoring whether or not the file name would be dateAndTime.ser. The writeObject(...) method of the ObjectOutputStream class facilitates the serialization process. As discussed previously, the I/O streams take care of the file-handling overhead.

Here is the code for creating the object from the file dateAndTime.ser.

import java.io.*;
import java.util.Calendar;
 
public class DeSerializeObject
{
   public static void main(String args[])
   {
      DateAndTimeObject dateAndTimeObject = null;
      FileInputStream fileInputStream = null;
      ObjectInputStream objectInputStream = null;
 
      String serializedFileName = "dateAndTime.ser";
      if(args.length > 0)
      {
         serializedFileName = args[0];
      }
 
      try
      {
         fileInputStream = new FileInputStream(serializedFileName);
         objectInputStream = new ObjectInputStream(fileInputStream);
         dateAndTimeObject = (DateAndTimeObject) objectInputStream.readObject();
         objectInputStream.close();
 
         //Date and Time that was serialized
         System.out.println("Serialize Date and Time: " + dateAndTimeObject.getDateAndTime());
         //Current Date and Time
         System.out.println("Current Date and Time  : " + Calendar.getInstance().getTime());
 
      }
      catch(FileNotFoundException fnfe)
      {
         System.out.println("File not found: "+fnfe.getMessage());
         //Close all I/O streams
         //Handle the exception here
      }
      catch(IOException ioe)
      {
         ioe.printStackTrace();
         //Close all I/O streams
         //Handle the exception here
      }
      catch(ClassNotFoundException cnfe)
      {
         cnfe.printStackTrace();
         //Close all I/O streams
         //Handle the exception here
      }
   }
}


Here is the output from the above listing.

The readObject(...) method of the ObjectInputStream class facilitates creating the object in the runtime from the serialized object.

Understanding Transient Keyword

The transient modifier is very handy in cases where you need to avoid serializing certain information from the object's state. Transient modifiers could be threads, database connections, sockets, I/O streams, etc. There is no point in serializing these objects, as their states could be indeterminable when they are recreated. It is also possible that the source for a database connection no longer exists.

Though using transient keywords effectively looks tough, it's fairly simple. You just need to associate the attribute with a transient keyword and the serialization API takes care of the rest. All attributes that are associated with the transient keyword will not be serialized when object serialization takes place.

Object Serializing with Your Own Protocol

Most Java applications are well served by their default serialization protocol, but developers still have a choice to customize the serialization protocol with their own. Java supports this is by implementing the Externalizable interface, which has two methods with the following signatures.

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


Here, you can adjust the implementation for serializing and de-serializing to meet your requirements. You could serialize the object and have other primitive data types with it as well. The de-serialization process is just the reverse of the serialization process. The most important aspect here is that the de-serialization implementation can be proprietary, which can be useful in addressing security concerns. You can ensure that the de-serialized object you have created is not tampered with by using hash codes, which you can maintain in a proprietary placeholder.

You can also serialize states of previously ignored objects, such as database connections, provided you are certain that the connection is available with the right set of parameters required to serialize the object. I do not advise this approach.

Here are a couple of other serialization advisories:

  • During de-serialization, it is never a good idea to create an instance of the object with values for its attributes. You need to always use the default constructor, which has no arguments. You can fill up values for all the object's attributes later when it is created.
  • Serialization has its own file I/O impact on application performance. Analyzing the procedure carefully reveals that the standard file I/O operations are performed during serialization and de-serialization, with the complications of file I/O hidden from the developer. Of course, if you used the Externalizable interface, this complication is still present.

Avoiding Serialization

In some cases, you should not allow the objects you expose to be serialized. This is easy to do as well. Just overwrite the methods for the Externalizable interface and provide no implementation to the writeExternal(...) and readExternal(...) methods. This will ensure that no one can serialize the object.

The requirement for avoiding serialization could be as simple as supporting the Singleton pattern or preventing confidential information from circulating as files. The objects that you expose could be used by others in their runtimes, but they could not use the data available in other applications that breach contract/security.

Not a New Technology

Serialization is not a new technology that developers will have to learn from scratch. It is an idea/concept that all you are exposed to in most of your applications when you use the I/O package. This is just an advanced form of that concept with most of the little hurdles of file I/O hidden. The most important takeaway here is that serialization can be customized to the algorithms that you need; thereby increasing the security of the serialized data.

Code Download

  • JavaSerialization_src.zip

    For Further Reading

  • "Java Object Serialization Specification" (PDF)
  • "The Wonders of Java Object Serialization" (from ACM.org)

    About the Author

    Sridhar M S is a Java developer from Bangalore, India. He holds a master's degree in Computer Science.
  • Sitemap | Contact Us

    Thanks for your registration, follow us on our social networks to keep up-to-date