Java Cookbook, Second Edition

Problem

You need to write and (later) read objects.

Solution

Use the object stream classes, ObjectInputStream and ObjectOutputStream. Or use XMLDecoder and XMLEncoder, or Java Data Objects.

Discussion

Object serialization is the ability to convert in-memory objects to an external form that can be sent serially (a byte at a time) and back again. The "and back again" may happen at a later time, or in another JVM on another computer (even one that has a different byte order); Java handles differences between machines. ObjectInputStream and ObjectOutputStream are specialized stream classes designed to read and write objects. They can be used to save objects to disk, as I'll show here, and are also useful in passing objects across a network connection, as I'll show in Recipe 16.6. This fact was not lost on the designers of remote method invocation, or RMI (see Chapter 22), which uses them for transporting the data involved in remote method calls.

As you might imagine, if we pass an object, such as a MyData object, to the writeObject( ) method, and writeObject( ) notices that one of the fields is itself a reference to an object such as a String, that data will get serialized properly. In other words, writeObject works recursively. So, we will give it a List of data objects. The first entry in this list is a java.util.Date, for versioning purposes. All remaining objects are of type MyData, a dummy class made up for this demonstration.

To be serializable, the data class must implement the empty Serializable interface. Also, the keyword transient can be used for any data that should not be serialized. You might need to do this for security or to prevent attempts to serialize a reference to an object from a nonserializable class. Here it is used to prevent unencrypted passwords from being saved where they might be readable:

/** Simple data class used in Serialization demos. */ public class MyData implements Serializable { String userName; String passwordCypher; transient String passwordClear; /** This constructor is required for use by JDO */ public MyData( ) { } public MyData(String name, String clear) { setUserName(name); setPassword(clear); } public String getUserName( ) { return userName; } public void setUserName(String s) { userName = s; } public String getPasswordCypher( ) { return passwordCypher; } /** Save the clear text p/w in the object, it won't get serialized * So we must save the encryption! Encryption not shown here. */ public void setPassword(String s) { this.passwordClear = s; passwordCypher = encrypt(passwordClear); } public String toString( ) { return "MyData[" + userName + "]"; } /** In real life this would use Java Cryptography */ protected String encrypt(String s) { return "fjslkjlqj2TOP+SECRETkjlskl"; } }

Since several methods are available for serializing, I define an abstract base class, called SerialDemoAbstractBase, which creates the data list and whose save( ) method calls the abstract write( ) method to actually save the data:

/** Demonstrate use of Serialization. Typical Subclass main will be: * public static void main(String[] s) throws Exception { * new SerialDemoZZZ( ).save( ); // in parent class; calls write * new SerialDemoZZZ( ).dump( ); * } */ public abstract class SerialDemoAbstractBase { /** The save method in an application */ public void save( ) throws IOException { List l = new ArrayList( ); // Gather the data l.add(new Date( )); l.add(new MyData("Ian Darwin", "secret_java_cook")); l.add(new MyData("Abby Brant Charles", "dujordian")); write(l); } /** Does the actual serialization */ public abstract void write(Object theGraph) throws IOException; /** Reads the file and displays it. */ public abstract void dump( ) throws IOException, ClassNotFoundException; }

The implementation for Object Stream serialization is shown here:

/** Demonstrate use of standard Object Serialization. */ public class SerialDemoObjectStream extends SerialDemoAbstractBase { protected static final String FILENAME = "serial.dat"; public static void main(String[] s) throws Exception { new SerialDemoObjectStream( ).save( ); // in parent class; calls write new SerialDemoObjectStream( ).dump( ); } /** Does the actual serialization */ public void write(Object theGraph) throws IOException { // Save the data to disk. ObjectOutputStream os = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream(FILENAME))); os.writeObject(theGraph); os.close( ); } public void dump( ) throws IOException, ClassNotFoundException { ObjectInputStream is = new ObjectInputStream( new FileInputStream(FILENAME)); System.out.println(is.readObject( )); is.close( ); } }

See Also

There are other ways to serialize objects, depending upon your storage/interchange goals. One way is to serialize using Java Data Objects (JDO), as discussed in Recipe 20.1. Another is to write the individual data members into an XML file, discussed in Recipe 21.1. The implementation classes for this demonstration are SerialDemoJDO and SerialDemoXML respectively.

Категории