Retired Document
Important: This document may not represent best practices for current development. Links to downloads and other resources may no longer be valid.
Serializing Objects and Data
XML Serialization Essentials explained that serialization is a useful way to implement component-to-component communication or application-to-application communication. This chapter guides you through the creation of a simple WebObjects application that shows how serialization, both binary-based and XML-based, can be implemented.
The chapter is divided in two sections:
Binary Serialization Example walks you through the creation of the Serialization project, which includes an example utility class called BinarySerializer, used to serialize objects and data into binary files.
XML Serialization Example shows how to use WebObjects XML serialization with the example class named XMLSerializer to serialize objects and data. It demonstrates that serializing to XML documents is just as easy as serializing to binary files. In addition, it teaches you how to include keys in the XML documents that represent serialized data. These keys can make it easier to transform those documents into a format that other applications expect. Finally, it explains the use of NSXMLOutputFormat objects to set output-format properties for NSXMLOutputStream objects.
Binary Serialization Example
This section guides you through the creation of a straightforward application that serializes and deserializes objects and primitive values into and from binary form using Java's binary-serialization facilities.
Creating the Serialization Project
Using Project Builder, create a WebObjects application project named Serialization. You don't need to add any frameworks to the project, such as the Java JDBC Adaptor framework. (You can look at the finalized project in projects/Serializing/Binary/Serialization
.)


Adding the BinarySerializer Class
The BinarySerializer class manages binary serialization and deserialization to and from files. To save yourself some typing, you can add the BinarySerializer.java
file in projects/Serializing/Binary/Serialization
to your project's Application Server target. Otherwise, follow the steps below.
Select the Classes group in the Serializer project.
Choose File > New File.
In the New File pane of the Project Builder Assistant, select Java Class under WebObjects and click Next.
In the New Java Class pane, name the class
BinarySerializer
and click Finish.Replace the template code in
BinarySerializer.java
with the code in BinarySerialization.java.
BinarySerializer.java
provides two main functions: serialization and deserialization of objects and creation and disposal of ObjectOutputStream and ObjectInputStream objects.
The serializeObject
and deserializeObject
methods serialize and deserialize objects to and from a file. You can use the openStream
and closeStream
methods to serialize primitive-type values or individual objects. See Serializing Primitive-Type Values to an XML Document for an example.
Serializing an NSArray of Strings
Now that you have the BinarySerializer class as part of your project, you can use it to serialize objects.
The first step is to add three methods to the Application class: one that instantiates, populates, and serializes an NSArray of Strings; a second one that deserializes and displays the data; and a third one that invokes the other two. Listing 3-1 shows the methods.
Listing 3-1 The serializeArray
, deserializeArray
, and arraySerialization
methods in Application.java
/** |
* Creates and serializes an NSArray of Strings. |
* @param identifier identifies the target file, without a |
* path or an extension |
*/ |
public void serializeArray(String identifier) { |
// Instantiate object to serialize. |
NSArray book_titles = new NSArray(new Object[] {"The Chestry Oak", "A Tree for Peter", "The White Stag"}); |
// Serialize the object. |
BinarySerializer.serializeObject(book_titles, identifier); |
} |
/** |
* Deserializes an NSArray and writes its contents to the console. |
* @param identifier identifies the source file, without a |
* path or an extension |
*/ |
public void deserializeArray(String identifier) { |
// Deserialize the data and assign it to an NSArray object. |
NSArray books = (NSArray)BinarySerializer.deserializeObject(identifier); |
// Display the contents of <code>books</code> on the console |
// (the Run pane in Project Builder). |
System.out.println(""); |
System.out.println("** Deserialized NSArray **"); |
System.out.println(books); |
System.out.println(""); |
} |
/** |
* Invokes the <code>serializeArray</code> and |
* <code>deserializeArray</code> methods. |
*/ |
public void arraySerialization() { |
String identifier = "BookTitles"; |
// Serialize NSArray object. |
serializeArray(identifier); |
// Deserialize NSArray object. |
deserializeArray(identifier); |
} |
Finally, modify the Application class's constructor so that it looks like Listing 3-2.
Listing 3-2 The constructor in Application.java
/** |
* Creates an Application object. Invoked once during application startup. |
*/ |
public Application() { |
super(); |
System.out.println("Welcome to " + this.name() + "!"); |
// Test serialization of an array. |
arraySerialization(); |
} |
After you build and run the application, Project Builder's Run pane should look similar to Listing 3-1.


If you open /tmp/BookTitles_data.binary
(generated by the serialization process) in a text editor, you should see something similar to Listing 3-2.
BinaryTitles_data.binary
file viewed through a text editor
This hardly qualifies as human-readable. XML Serialization Essentials shows you how to create files with serialized data that are easier for people to read and modify.
Serializing Primitive-Type Values
This section shows you how to serialize primitive-type values that are not encapsulated by objects. To accomplish this, you instantiate an ObjectOutputStream and invoke one or more of its write
methods.
Add three methods to the Application class of the Serialization project: one that serializes values of type int
, boolean
, char
and double
; a second that deserializes the data; and a third one that calls the other two. Listing 3-3 gives you an example of such methods.
Listing 3-3 The serializePrimitives
, deserializePrimitives
, and primitiveSerialization
methods in Application.java
/** |
* Serializes a set of primitive values. |
* |
* @param filename identifies the target file, including its |
* path and extension |
* |
* @param an_int value to serialize |
* @param a_boolean value to serialize |
* @param a_char value to serialize |
* @param a_double value to serialize |
*/ |
public void serializePrimitives(String filename, int an_int, boolean a_boolean, char a_char, double a_double) { |
try { |
// Open an output stream. |
ObjectOutputStream stream = BinarySerializer.openOutputStream(filename); |
// Write values. |
stream.writeInt(an_int); |
stream.writeBoolean(a_boolean); |
stream.writeChar(a_char); |
stream.writeDouble(a_double); |
// Close the stream. |
BinarySerializer.closeStream(filename); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
} |
/** |
* Deserializes a set of primitive values. |
* |
* @param filename identifies the source file, including its |
* path and extension |
*/ |
public void deserializePrimitives(String filename) { |
try { |
// Open an input stream. |
ObjectInputStream stream = BinarySerializer.openInputStream(filename); |
// Read values. |
int the_int = stream.readInt(); |
boolean the_boolean = stream.readBoolean(); |
char the_char = stream.readChar(); |
double the_double = stream.readDouble(); |
BinarySerializer.closeStream(filename); |
// Write values to console (Run pane in Project Builder). |
System.out.println(""); |
System.out.println("** Deserialized primitives **"); |
System.out.println("int: " + the_int); |
System.out.println("boolean: " + the_boolean); |
System.out.println("char: " + the_char); |
System.out.println("double: " + the_double); |
System.out.println(""); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
} |
/** |
* Invokes the <code>serializePrimitives</code> and |
* <code>deserializePrimitives</code> methods. |
*/ |
public void primitiveSerialization() { |
String filename = "/tmp/PrimitiveValues_data.binary"; |
// Serialize primitive values. |
serializePrimitives(filename, 5, true, 'u', 3.14); |
// Deserialize primitive values. |
deserializePrimitives(filename); |
} |
You also need to add the following to the Application class:
import java.io.IOException; |
import java.io.ObjectInputStream; |
import java.io.ObjectOutputStream; |
Finally, add a call to the primitiveSerialization
method in the Application class's constructor:
// Test serialization of primitive values. |
primitiveSerialization(); |
Build and run the application. Project Builder's Run pane should look similar to Listing 3-3.


Serializing Custom Objects
Now that you've mastered the art of serializing an instance of a WebObjects Serializable class and primitive-type values, you're ready to tackle the serialization of custom objects. For this, you create a Movie class that includes writeObject
and readObject
methods.
Add a class named Movie to the Serialization project and assign it to the Application Server target. Modify Movie.java
so that it looks like Listing 3-4. (Alternatively, you can add the Movie.java
file in projects/Serializing/Binary/Serialization
to your project.)
Listing 3-4 Movie.java
using binary serialization
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
import com.webobjects.foundation.xml.*; |
import com.webobjects.eocontrol.*; |
import java.io.IOException; |
import java.io.ObjectInputStream; |
import java.io.ObjectOutputStream; |
import java.io.Serializable; |
import java.sql.Timestamp; |
/** |
* Manages movie information. |
*/ |
public class Movie extends Object implements Serializable { |
private String title; |
private String studio; |
private NSTimestamp releaseDate; |
/** |
* Creates a Movie object. |
* |
* @param name movie title |
* @param studio studio that released the movie |
* @param release_date date the movie was released |
*/ |
Movie(String title, String studio, NSTimestamp releaseDate) { |
super(); |
setTitle(title); |
setStudio(studio); |
setReleaseDate(releaseDate); |
} |
/** |
* Gets this movie's title. |
* |
* @return movie title. |
*/ |
public String title() { |
return this.title; |
} |
/** |
* Sets this movie's title. |
* |
* @param value movie's title |
*/ |
public void setTitle(String value) { |
this.title = value; |
} |
/** |
* Gets this movie's studio. |
* |
* @return movie studio. |
*/ |
public String studio() { |
return this.studio; |
} |
/** |
* Sets this movie's studio. |
* |
* @param value studio's name |
*/ |
public void setStudio(String value) { |
this.studio = value; |
} |
/** |
* Gets this movie's release date. |
* |
* @return movie release date. |
*/ |
public NSTimestamp releaseDate() { |
return this.releaseDate; |
} |
/** |
* Sets this movie's release date. |
* |
* @param value release date |
*/ |
public void setReleaseDate(NSTimestamp value) { |
this.releaseDate = value; |
} |
/** |
* Gets the string representation of this movie. |
* |
* @return string representing this movie. |
*/ |
public String toString() { |
return "(Movie: (Title: " + title() + "), (Studio: " + studio() + "), (Release Date: " + releaseDate().toString() + "))"; |
} |
/** |
* Serializes this object. |
* |
* @param stream object stream to serialize this object to |
*/ |
private void writeObject(ObjectOutputStream stream) throws IOException { |
// Serialize the object's instance members. |
// (This is where you put special encoding logic, |
// such as the one used to encode the releaseDate field.) |
stream.writeObject(title()); |
stream.writeObject(studio()); |
stream.writeObject(releaseDate().toString()); |
} |
/** |
* Deserializes this object. |
* |
* @param stream object stream from which the serialized data |
* is obtained |
*/ |
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { |
// Deserializes the data a put it in the object's instance members. |
// (This is where you would put special de-encoding logic |
// such as the one used to decode the releaseDate field.) |
setTitle((String)stream.readObject()); |
setStudio((String)stream.readObject()); |
setReleaseDate(_timestampFromString((String)stream.readObject())); |
} |
/** |
* Converts a string into an NSTimestamp. |
* |
* @param timestampAsString string to convert |
* |
* @return NSTimestamp object represented by timestampAsString. |
*/ |
private NSTimestamp _timestampFromString(String timestampAsString) { |
NSTimestampFormatter formatter = new NSTimestampFormatter(); |
java.text.ParsePosition pp = new java.text.ParsePosition(0); |
return (NSTimestamp)formatter.parseObject(timestampAsString, pp); |
} |
} |
Now add the methods in Listing 3-5 to Application.java
.
Listing 3-5 The serializeMovie
, deserializeMovie
, and movieSerialization
methods in Application.java
/** |
* Serializes a Movie object. |
* |
* @param identifier identifies the target file, without a |
* a path or an extension |
*/ |
public void serializeMovie(String identifier) { |
// Set the local time zone. |
NSTimeZone timeZone = NSTimeZone.timeZoneWithName("America/Los_Angeles", true); |
Movie movie = new Movie("Alien", "20th Century Fox", new NSTimestamp(1979, 10, 25, 0, 0, 0, timeZone)); |
BinarySerializer.serializeObject(movie, identifier); |
} |
/** |
* Deserializes Movie data into an object. |
* |
* @param identifier identifies the source file, without a |
* a path or an extension |
*/ |
public void deserializeMovie(String identifier) { |
Movie movie = (Movie)BinarySerializer.deserializeObject(identifier); |
System.out.println(""); |
System.out.println("** Deserialized Movie object **"); |
System.out.println(movie.toString()); |
System.out.println(""); |
} |
/** |
* Invokes the <code>movieSerialization</code> and |
* <code>movieDeserialization</code> methods. |
*/ |
public void movieSerialization() { |
String identifier = "Movie"; |
serializeMovie(identifier); |
deserializeMovie(identifier); |
} |
Finally, modify the Application class's constructor by adding a call to the movieSerialization
method:
// Serialize a Movie object. |
movieSerialization(); |
After building and running the application, you should see something similar to Listing 3-4.


The remainder of the section shows you how to serialize an NSMutableArray of Movies and deserialize the data into an NSArray.
Add the methods shown in Listing 3-6 to Application.java
.
Listing 3-6 The serializeMovieArray
, deserializeMovieArray
, and movieArraySerialization
methods of Application.java
/** |
* Serializes a Movie array. |
* |
* @param identifier identifies the target file, without a |
* a path or an extension |
*/ |
public void serializeMovieArray(String identifier) { |
// Set the local time zone. |
NSTimeZone timeZone = NSTimeZone.timeZoneWithName("America/Los_Angeles", true); |
// Initialize the array. |
NSMutableArray movies = new NSMutableArray(); |
movies.addObject(new Movie("Alien", "20th Century Fox", new NSTimestamp(1979, 10, 25, 0, 0, 0, timeZone))); |
movies.addObject(new Movie("Blade Runner", "Warner Brothers", new NSTimestamp(1982, 1, 3, 0, 0, 0, timeZone))); |
movies.addObject(new Movie("Star Wars", "20th Century Fox", new NSTimestamp(1977, 12, 29, 0, 0, 0, timeZone))); |
// Serialize the array. |
BinarySerializer.serializeObject(movies, identifier); |
} |
/** |
* Deserializes Movie data into an NSArray. |
* |
* @param identifier identifies the source file, without a |
* a path or an extension |
*/ |
public void deserializeMovieArray(String identifier) { |
// Create an empty array. |
NSArray movies = new NSArray(); |
// Deserialize data into movies. |
movies = (NSArray)BinarySerializer.deserializeObject(identifier); |
System.out.println(""); |
System.out.println("** Deserialized Movie array **"); |
System.out.println(movies.toString()); |
System.out.println(""); |
} |
/** |
* Invokes the <code>movieArraySerialization</code> and |
* <code>movieArrayDeserialization</code> methods. |
*/ |
public void movieArraySerialization() { |
String identifier = "Movies"; |
serializeMovieArray(identifier); |
deserializeMovieArray(identifier); |
} |
Add a call to the movieArraySerialization
method in the Application class's constructor and build and run the application. The Project Builder Run pane should look like Listing 3-5.


XML Serialization Example
As you learned in XML Serialization Essentials WebObjects XML serialization works essentially the same way Java binary serialization does. This section shows how to modify the Serialization project so that it uses a new class, XMLSerializer, to serialize and deserialize objects and data.
If you did not create the Serialization project in Binary Serialization Example, you can get it from this document's example projects in projects/Serializing/Binary
.
Adding the XMLSerializer Class
Start by adding a new class called XMLSerializer.java
to the project and assigning it to the Application Server target. Then modify the class so that it looks like XMLSerializer.java. (Alternatively, you can add the XMLSerializer.java
file in projects/Serializing/XML/Serialization
to your project.)
Serializing an NSArray of Strings to an XML Document
Now that the Serialization project contains the utility class XMLSerializer, modify the serializeArray
and deserializeArray
methods in Application.java
so that they look like Listing 3-7. (All you need to do is change occurrences of BinarySerializer
to XMLSerializer
in the lines numbered 1 and 2.)
Listing 3-7 The serializeArray
and deserializeArray
methods in Application.java
using XML serialization
/** |
* Creates and serializes an NSArray of Strings. |
* @param identifier identifies the target file, without a |
* path or an extension |
*/ |
public void serializeArray(String identifier) { |
// Instantiate object to serialize. |
NSArray book_titles = new NSArray(new Object[] {"The Chestry Oak", "A Tree for Peter", "The White Stag"}); |
// Serialize the object. |
XMLSerializer.serializeObject(book_titles, identifier); |
} |
/** |
* Deserializes an NSArray and writes its contents to the console. |
* @param identifier identifies the source file, without a |
* path or an extension |
*/ |
public void deserializeArray(String identifier) { |
// Deserialize the data and assign it to an NSArray object. |
NSArray books = (NSArray)XMLSerializer.deserializeObject(identifier); |
// Display the contents of <code>books</code> on the console |
// (the Run pane in Project Buider). |
System.out.println(""); |
System.out.println("** Deserialized NSArray **"); |
System.out.println(books); |
System.out.println(""); |
} |
After building and running the application, you can find the BookTitles_data.xml
file (shown in Listing 3-8) in /tmp
.
Listing 3-8 BookTitles_data.xml
(serialized array of Strings)
<?xml version="1.0" encoding="UTF-8"?> |
<content xmlns="http://www.apple.com/webobjects/XMLSerialization" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema- |
instance" xsi:schemaLocation="http://www.apple.com/webobjects/XMLSerialization |
http://www.apple.com/webobjects/5.2/schemas/woxml.xsd"> |
<object id="2"> |
<class flag="3" id="0" name="com.webobjects.foundation.NSArray" suid="- |
3789592578296478260"> |
<field name="objects" type="java.lang.Object[]"/> |
</class> |
<array field="objects" id="4" ignoreEDB="1" length="3" type="java.lang.Object[]"> |
<string id="5">The Chestry Oak</string> |
<string id="6">A Tree for Peter</string> |
<string id="7">The White Stag</string> |
</array> |
</object> |
</content> |
As you can see, the serialized version of the NSArray object is easier to read than BookTitles_data.binary
, created in Serializing an NSArray of Strings. Listing 3-6 graphically depicts BookTitles_data.xml
. However, the document is somewhat verbose. Transforming XML Documents shows you how to transform XML streams generated by NSXMLOutputStream into streamlined XML documents.
BoolTitles_data.xml
document
Serializing Primitive-Type Values to an XML Document
By now you've probably noticed how easy it is to serialize objects into XML documents. This section shows you how to serialize primitive-type values.
First, add the following code line to Application.java
:
import com.webobjects.foundation.xml.*; |
Now, modify the serializePrimitives
and deserializePrimitives
methods so that they match Listing 3-9 (You need to modify only the five numbered lines.)
Listing 3-9 The serializePrimitives
, deserializePrimitives
and primitiveSerialization
methods in Application.java
using XML serialization
/** |
* Serializes a set of primitive values. |
* |
* @param filename identifies the target file, including its |
* path and extension |
* @param an_int value to serialize |
* @param a_boolean value to serialize |
* @param a_char value to serialize |
* @param a_double value to serialize |
*/ |
public void serializePrimitives(String filename, int an_int, boolean a_boolean, |
char a_char, double a_double) { |
try { |
// Open an output stream. |
NSXMLOutputStream stream = XMLSerializer.openOutputStream(filename, null); |
// Write values. |
stream.writeInt(an_int); |
stream.writeBoolean(a_boolean); |
stream.writeChar(a_char); |
stream.writeDouble(a_double); |
// Close the stream. |
XMLSerializer.closeStream(filename); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
} |
/** |
* Deserializes a set of primitive values. |
* |
* @param filename identifies the source file, including |
* its path and extension |
*/ |
public void deserializePrimitives(String filename) { |
try { |
// Open an input stream. |
NSXMLInputStream stream = XMLSerializer.openInputStream(filename); |
// Read values. |
int the_int = stream.readInt(); |
boolean the_boolean = stream.readBoolean(); |
char the_char = stream.readChar(); |
double the_double = stream.readDouble(); |
XMLSerializer.closeStream(filename); |
// Write values to console (Run pane in Project Builder). |
System.out.println(""); |
System.out.println("** Deserialized primitives **"); |
System.out.println("int: " + the_int); |
System.out.println("boolean: " + the_boolean); |
System.out.println("char: " + the_char); |
System.out.println("double: " + the_double); |
System.out.println(""); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
} |
/** |
* Invokes the <code>serializePrimitives</code> and |
* <code>deserializePrimitives</code> methods. |
*/ |
public void primitiveSerialization() { |
String filename = "/tmp/PrimitiveValues_data.xml"; |
// Serialize primitive values. |
serializePrimitives(filename, 5, true, 'u', 3.14); |
// Deserialize primitive values. |
deserializePrimitives(filename); |
} |
Notice the signature of the openOutputStream
method of the XMLSerializer class (Listing B-2):
openOutputStream(String filename, String transformation) throws IOException; |
The invoking code specifies the type of transformation to perform on the serialized data through the transformation parameter. In this case, however, serializePrimitives
does not perform a transformation; therefore, it invokes openOutputStream
with transformation set to null
. See XML Transformation for more information on transforming XML documents.
After building and running the application, your /tmp
directory should contain the PrimitiveValues_data.xml
. file. Listing 3-10 shows its contents.
Listing 3-10 The PrimitiveValues_data.xml
file
<?xml version="1.0" encoding="UTF-8"?> |
<content xmlns="http://www.apple.com/webobjects/XMLSerialization" xmlns:xsi="http://www.w3.org/2001/ |
XMLSchema-instance" xsi:schemaLocation="http://www.apple.com/webobjects/ |
XMLSerialization |
http://www.apple.com/webobjects/5.2/schemas/woxml.xsd"> |
<int>5</int> |
<boolean>true</boolean> |
<ch>u</ch> |
<double>3.14</double> |
</content> |
Serializing With Keys
Keys can help a great deal in describing what a data element represents. Adding keys to values as they are serialized is a simple process. Modify serializePrimitives
so that it looks like Listing 3-11 (change the numbered code lines), and build and run the application.
Listing 3-11 The serializePrimitives
method of Application.java
using keys to identify elements in XML document
public void serializePrimitives(String filename, int an_int, boolean a_boolean, char a_char, double a_double) { |
try { |
// Open an output stream. |
NSXMLOutputStream stream = XMLSerializer.openOutputStream( |
filename, null); |
// Write values. |
stream.writeInt(an_int, "my_integer"); |
stream.writeBoolean(a_boolean, "my_boolean"); |
stream.writeChar(a_char, "my_char"); |
stream.writeDouble(a_double, "my_double"); |
// Close the stream. |
XMLSerializer.closeStream(filename); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
} |
Now, after building and running the project, the PrimitiveValues_data.xml
file looks like Listing 3-12.
Listing 3-12 The PrimitiveValues_data.xml
file with keys identifying each element
<?xml version="1.0" encoding="UTF-8"?> |
<content xmlns="http://www.apple.com/webobjects/XMLSerialization" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xsi:schemaLocation="http://www.apple.com/webobjects/XMLSerialization |
http://www.apple.com/webobjects/5.2/schemas/woxml.xsd"> |
<int key="my_integer">5</int> |
<boolean key="my_boolean">true</boolean> |
<ch key="my_char">u</ch> |
<double key="my_double">3.14</double> |
</content> |
The code in Transforming Primitive-Type Values Using Keys takes advantage of the key
attribute on each element of the content
element to transform the source XML document in Listing 3-12 to one that uses the values of those keys as the tag names of the elements that contain the data values in the target document, shown in Listing 5-6.
Serializing Custom Objects to an XML Document
You can take advantage of keys in custom Serializable objects by invoking the writeObject(Object, String)
method of NSXMLOutputStream in the writeObject
method of your custom class. To accomplish this, however, you have to cast the ObjectOutputStream argument to NSXMLOutputStream before invoking the writeObject(Object, String)
method.
Modify the writeObject
method of Movie.java
so that it looks like Listing 3-13.
Listing 3-13 The writeObject
method in Movie.java
using XML serialization with keys
private void writeObject(ObjectOutputStream stream) throws IOException { |
// Serialize the object's instance members. |
// (This is where you put special encoding logic; |
// this example doesn't perform any special encoding.) |
// Cast stream to NSXMLOutputStream to gain access to |
// <code>writeObject(Object, String)</code>. |
NSXMLOutputStream xml_stream = (NSXMLOutputStream)stream; |
xml_stream.writeObject(title(), "title"); |
xml_stream.writeObject(studio(), "studio"); |
xml_stream.writeObject(releaseDate().toString(), "release_date"); |
} |
Now, modify the serializeMovie
, deserializeMovie
, serializeMovieArray
and deserializeMovieArray
methods in Application.java
so that they use the XMLSerializer class's serializeObject
and deserializeObject
methods, respectively.
Build and run the application. If you open /tmp/Movies_data.xml
in a text editor, you'll see something similar to the contents of Listing 3-14. Notice the key
attribute included in the data elements of each object
element corresponding to a Movie object. The key
attribute is used by the transformation script in Transforming an Array of Movies to generate the data elements of the target document.
Also notice that the third Movie object in Movies_data.xml
(starting at the line numbered 2) contains a reference to the studio defined in the first Movie object (the line numbered 1) instead of the name of the studio. This is how multiple references to the same object are represented in XML documents generated by NSXMLOutputStream.
Listing 3-14 The Movies_data.xml
file
<?xml version="1.0" encoding="UTF-8"?> |
<content xmlns="http://www.apple.com/webobjects/XMLSerialization" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.apple.com/webobjects/XMLSerialization |
http://www.apple.com/webobjects/5.2/schemas/woxml.xsd"> |
<object id="3"> |
<class flag="2" id="0" |
name="com.webobjects.foundation.NSMutableArray" suid="-3909373569895711876"> |
<super flag="3" id="1" |
name="com.webobjects.foundation.NSArray" suid="-3789592578296478260"> |
<field name="objects" type="java.lang.Object[]"/> |
</super> |
</class> |
<array field="objects" id="5" ignoreEDB="1" length="3" type="java.lang.Object[]"> |
<object id="10"> |
<class flag="3" id="6" name="Movie" suid="-791832868721905865"> |
<field name="releaseDate" type="com.webobjects.foundation.NSTimestamp"/> |
<field name="studio" type="java.lang.String"/> |
<field name="title" type="java.lang.String"/> |
</class> |
<string id="11" key="title" xml:space="preserve">Alien</string> |
<string id="12" key="studio" xml:space="preserve">20th Century Fox</string> |
<string id="13" ignoreEDB="1" key="release_date" xml:space="preserve">1979-10-25 07:00:00 Etc/GMT</string> |
</object> |
<object id="14"> |
<class idRef="6" name="Movie"/> |
<string id="15" key="title" xml:space="preserve">Blade Runner</string> |
<string id="16" key="studio" xml:space="preserve">Warner Brothers</string> |
<string id="17" ignoreEDB="1" key="release_date" xml:space="preserve">1982-01-03 08:00:00 Etc/GMT</string> |
</object> |
<object id="18"> |
<class idRef="6" name="Movie"/> |
<string id="19" key="title" xml:space="preserve">Star Wars</string> |
<string idRef="12" key="studio"/> |
<string id="20" ignoreEDB="1" key="release_date" xml:space="preserve">1977-12-29 08:00:00 Etc/GMT</string> |
</object> |
</array> |
</object> |
</content> |
Formatting Serialized Output
The XML documents produced so far are nicely indented to facilitate their comprehension by people. However, most of the time, these documents are intended for applications. Therefore, indentation (and the extra characters it adds to a stream) is not needed. You can determine whether the output produced by an NSXMLOutputStream object is indented using a NSXMLOutputFormat (com.webobjects.foundation.xml
) object. NSXMLOutputFormat objects encapsulate formatting information that can be applied to an NSXMLOutputStream object.
Table 3-1 lists the output-format properties you can set with NSXMLOutputFormat.
Property | Description | Default value |
---|---|---|
Determines the encoding used in the document. |
| |
Determines whether the XML document generated is indented. |
| |
Determines whether the XML declaration is omitted from the document. |
| |
Determines the document's XML version. |
|
You can use WebObjects-style accessors to get and set the values of the properties listed in Table 3-1. The value of the indenting
property can also be set through one of the constructors of NSXMLOutputFormat, NSXMLOutputFormat(boolean)
.
Listing 3-15 shows a method that creates an XML stream to a file and sets the indenting
and encoding
properties for the stream.
Listing 3-15 Setting the indenting
and encoding
properties of an NSXMLOutputFormat object and applying them to an NSXMLOutputStream object
/** |
* Opens an XML output stream to a file. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to open |
* |
* @return object stream, <code>null</code> when the stream |
* could not be created. |
*/ |
public Object xmlOutputStream(String filename) throws IOException { |
BufferedOutputStream file_output_stream; |
NSXMLOutputStream xml_stream; |
NSXMLOutputFormat format; |
// Create an output stream to the file. |
file_output_stream = new BufferedOutputStream(new FileOutputStream(filename)); |
// Create object output stream. |
xml_stream = new NSXMLOutputStream(file_output_stream); |
// Set the format of the output document. |
format = new NSXMLOutputFormat(true); // turn indentation on |
format.setEncoding("UTF-16"); // set encoding to UTF-16 |
xml_stream.setOutputFormat(format); // apply format to the stream |
return xml_stream; |
} |
For more information on NSXMLOutputFormat, see the API documentation.
Copyright © 2002, 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-08-11