Object Serialization in Java 1.1
Making Objects Persistent
By Chad Darby
Java 1.1 introduces object serialization, an easy-to-use and easy-to-implement data-storage method that eliminates worries about file formats. Object serialization lets you save an object's state, thereby saving the values of the data members and functionality of the methods. In effect, this provides object "persistence." Say, for example, you are writing a computer game with a save option. If the player's state information -- position, score, and so on -- is maintained in a game object, you can simply serialize that object to a disk file. The serialization will recursively save all objects pointed to by the game object; then, when the player restarts the game, only the game object must be reloaded.
In this article we will step through object serialization using a simple class, then focus on its implementation in a real-world application. (For more on object serialization, see Bruce Eckel's July 1997 "Java Alley" column in Web Techniques.)
Customer Class Design
To illustrate serializing an object, we will use a simple
Customer class that holds a customer's name and age; see
Figure 1. The class will override the
toString() method to provide a string representation; however, the real meat of this example will be in the
save() methods, which provide the actual code for reading and writing serialized objects.
To read or write the state of an object to or from a stream, the class must implement the
java.io.Serializable interface. This interface does not contain any methods or static data members; it is merely a tag indicating that the class can be serialized.
Listing One contains the skeleton class declaration of
Writing Objects to a Stream
Writing objects to a stream resembles writing primitives to output streams and involves the following steps:
- Create a
FileOutputStream object for the data file.
- Create an
ObjectOutputStream using the specified
- Write the object to the stream.
- Close the stream.
Customer class has a
save() method that will contain the code for writing the object to a stream; see
save() method takes as its parameter a filename that is then used to create the object's
FileOutputStream, which is in turn used to create an
ObjectOutputStream writes the object to the stream with the simple call
IOException will be thrown if the file cannot be opened for writing or if problems are encountered while accessing the object or its fields. The
throws keyword is used to list the exceptions the method can throw, forcing the programmer using the
Customer class to handle the exception(s).
After the object is written, we flush and close the
ObjectOutputStream, and the object is saved to a file.
To save an instance of the
Customer class to disk, we simply call its
save() method and pass a filename string.
Reading Objects from a Stream
Serialization makes it easy to read objects from an object stream: Calling the
readObject() method returns the state of a saved object, regardless of the format in which it was saved.
Reading an object from an input stream entails the following steps:
- Creating a
FileInputStream for the data file.
- Creating an
ObjectInputStream using the specified
- Reading from the input stream.
- Closing the stream.
load() method takes a filename as a parameter and returns a
Customer object; see
Listing Three. A
ObjectInputStream are created in a fashion similar to the
save() method. The statement
tempCustomer=(Customer) ois .readObject(); reads the object from the stream, after which it must be cast to our class. If a compatible class is not found, the
ClassNotFoundException is thrown. An
IOException may also be thrown since we are dealing with file I/O. Again, because of the
throws keyword in the method declaration, the programmer must handle the exceptions
IOException when calling the
load() method is declared as static and is therefore available class-wide. You can call static methods without referencing any particular object, so they are commonly used for "utility" methods. In this case,
load() is a utility for the
Customer class; because it is static, we can easily call it from our driver using
anyCustomer=Customer.load("foo.bar");. After the object is read, we can close the
Putting It All Together
Having added the functionality needed for object persistence to our
Customer class, we now need a driver to test it. In the driver, we will create one customer object and save it to a file, then load the object from the file and display the contents.
Listing Four gives the code for the Customer Driver. Two objects of
Customer are declared:
customerB. We create a new
Customer object and pass it the initial values
age=24. Then we save
customerA to the disk file foo.bar. By saving the object, we are in fact serializing it.
The object is loaded from foo.bar by calling the
load() method and passing in the filename. The
load() method returns a
Customer object, which is assigned to
load() is static, we don't have to reference a particular
Customer object, only the class name. In this example, the
load() method actually deserializes the object from the input stream.
Now that we have successfully loaded an object from the input stream, we can call its methods. The
System.out.println() statement calls the
toString() method, which accesses the object's data members and displays its contents. Additional public methods or data can also be referenced.
This simple example of object serialization used the default methods
readObject(); to control the information saved or restored, they could have been overridden. Furthermore, instead of the
Serializable interface, we could have implemented the
Externalizable interface, which saves only the class's identity; the class would then have to provide methods to save and restore the contents.
A Web-Based Reporting System
Now I'll move on to a real-world example: implementing object serialization to serve as a light-weight database and create dynamic Web pages based on the data stored in the serialized objects.
My intranet object-serialization example takes place at a fictional company called Mikar Tech. The Information Technology (IT) shop at Mikar Tech would like a Web-based collaborative reporting application. The company is in the process of installing a new sales-support system for their four regional divisions, and the Web application will give them the capability to monitor and update the project status.
Key members of the IT shop agreed that the Web application should provide the following functionality:
- 1. The ability for regional project managers to provide weekly reports via a Web-based form.
- 2. The ability to view a one-page summary of all weekly reports with "stop-light" status indicators.
- 3. The ability to drill down through the summary to get detailed information.
A traditional HTML form on the client side will be used to gather data for the weekly reports. The data will then be submitted to a Java-CGI program residing on the Web server; see
Figure 2. This Java-CGI program will perform the following:
- Store the weekly reports based on the form data as a serialized object.
- Create a dynamic Web page for weekly reports and save to disk.
- Create a dynamic Web page for summary reports based on all weekly reports submitted and save the page to disk.
- Return the weekly report page to the user for viewing.
The main driver of the Java-CGI application is the
StatusUpdate makes the high-level calls to produce the functionality outlined in the design.
Listing Five is the code fragment for the
main routine in the
The Weekly Report
Each week, the regional project managers will submit a weekly report via a Web-based form. The weekly report is composed of status ratings on project features: client software, database server, Internet connectivity, and user training.
When the manager rates the status of each feature, they will use red, yellow, or green. For example, if the client software has not been installed, this feature will be assigned red. If work is in progress, the feature will be rated yellow. Finally, if a feature is completed, it is rated green. This assignment of color codes gives the ability to provide a stop-light grid for the summary report.
After the project manager enters the data for the weekly report and submits the report, the Java-CGI program will perform the following functions:
- Stores the weekly report based on the form data as a serialized object.
- Creates a dynamic Web page for the weekly report and saves it to disk.
The Weekly Report as a Serialized Object
During the object-oriented analysis and design phase, three classes were identified as the heart and soul of the system; see
Figure 3 and
4. Each division's weekly report data needs to be stored. A
Division object will contain the name of the division (Seattle, WA), a pointer to the division's
ProjectManager and a list of all the project features. By leveraging object serialization, we can easily save the state of this object.
Since we only had four company divisions to handle, it would have been overkill to use relational-database access. By using object serialization, we did not waste valuable development time creating a scheme to read and write the data to a disk. Object serialization eliminated the need to save program information to flat text files or add relational-database connectivity.
To save the state of the
Division object, you need to provide a method for
load() for the
Listing Six is code fragment for the
save() method. Enhancements were made for saving the object to a data directory and a very simple file-locking mechanism was added. (Code for the
load() method will be discussed in a later section.)
save() method for the
Division object is called, the complete state data for the object is stored in a file titled <division>.division (for example, Seattle.division).
After the division's weekly report is saved as a serialized object, a dynamic Web page can be created. The
Division class has a
publishWeeklyReport() method, which actually calls a number of utility routines to build the different portions of an HTML page: heading, navigation bar, body, and the bottom. The heart of this method is in the call to
Listings Seven and
Eight provide the code for
Feature class provides a method to
WebString(), which gives an HTML-formatted string of its data members (see
The HTML tags are embedded in the string. This string information is returned to the calling method while the string is used to build the weekly report Web page. This Web page is saved to disk as a flat text file. Since this file has HTML tags, it can later be viewed by a Web browser.
The Project Summary Report
The project summary report is a one-page summary of all weekly reports. The summary gives a graphical display of the weekly reports with "stop-light" status indicators. This report is useful for determining the project status of all divisions at a glance. While viewing the summary report, the user can drill down for specific details in problem areas.
Creating the project-summary report involves loading serialized objects for all divisions and generating HTML tables with data from
Loading serialized objects. To create the summary report, the serialized object for all divisions must first be loaded. This load process is easy thanks to serialized objects. The
load() method is very similar to what was presented in the "how-to" section of this article. Enhancements were made for saving the object to a data directory and again, we implemented a simple file-locking mechanism (see
Loading division objects. To load all of the
Division objects, you can simply write a
for loop that calls the
load() method for each one. The
Division objects will be stored in a
Vector, which is a growable array.
Listing Eleven is the code fragment for loading the
Division objects. This method is a member of the
StatusUpdate class, which serves as the main driver for the application.
HTML Table for Summary Report
Basically, the summary report is a table that lists the project data for each division. Every time a new weekly report is submitted, the status grid must update to display the latest information (see
The bulk of the code is in the
buildGrid() method, which actually traverses the vector of
Division objects and creates an HTML table with the data (see
The normal HTML tag for a table is
border=1 width=100%>. For the first row of the table, we create a heading by listing the names of each
Division object. Each
Division object has a
nameToGridString() method that returns the name of the
Division object with HTML table tags (for example,
Once the grid heading is created, the data will be listed for each feature of the project (Client Software, Database Server, Internet Connectivity and User Training). Each
Feature object has a
statusToGridString() method that will return a string representation of the status. The actual string has HTML table code to display a GIF image. So, for example, if we had the following data for a feature:
Division Name: Houston
Feature Name: User Training
Feature Status: red
the HTML string returned would look like
Example 1. After all of the features are displayed, a final row is added at the bottom to display the date of the last report update.
When users view the HTML table, they will be able to get the project status of all divisions at a glance. If they want details on a specific problem area, clicking on the status image will allow them to drill down to the details on the weekly report created earlier.
Equipped with the knowledge about implementing serialized objects, you can easily integrate the Java object-serialization technology in your next Intranet application. The full source code is available at www.j-nine.com/pubs/Webtech-sep97.
(Get the source code for this article here.)
Chad (shod) is the principal consultant at J9 Consulting, www.j-nine.com, where he specializes in developing server-side Java applications. He can be reached at email@example.com.