[TOC] [Prev] [Next]

# Object Output Interfaces

### Topics:

- The ObjectOutputStream Class
- The writeObject Method
- The writeExternal Method

# The ObjectOutputStream Class

Class `ObjectOutputStream` implements object serialization. It maintains the state of the stream including the set of objects already serialized. Its methods control the traversal of objects to be serialized to save the specified objects and the objects to which they refer.

    package java.io;

    public class ObjectOutputStream
    	extends OutputStream
    	implements ObjectOutput, ObjectStreamConstants
    {
    	public ObjectOutputStream(OutputStream out)
    		throws IOException;

    	public final void writeObject(Object obj)
    		throws IOException;

    	public final void defaultWriteObject();
    		throws IOException, NotActiveException;

    	public void reset() throws IOException;

    	protected void annotateClass(Class cl) throws IOException;

    	protected Object replaceObject(Object obj) throws IOException;

    	protected final boolean enableReplaceObject(boolean enable)
    		throws SecurityException;

    	protected void writeStreamHeader() throws IOException;

    	public void write(int data) throws IOException;

    	public void write(byte b[]) throws IOException;

    	public void write(byte b[], int off, int len) throws IOException;

    	public void flush() throws IOException;

    	protected void drain() throws IOException;

    	public void close() throws IOException;

    	public void writeBoolean(boolean data) throws IOException;

    	public void writeByte(int data) throws IOException;

    	public void writeShort(int data)  throws IOException;

    	public void writeChar(int data)  throws IOException;

    	public void writeInt(int data)  throws IOException;

    	public void writeLong(long data)  throws IOException;

    	public void writeFloat(float data) throws IOException;

    	public void writeDouble(double data) throws IOException;

    	public void writeBytes(String data) throws IOException;

    	public void writeChars(String data) throws IOException;

    	public void writeUTF(String data) throws IOException;
    }

The `ObjectOutputStream` constructor requires an OutputStream. The constructor calls `writeStreamHeader` to write a magic number and version to the stream, that will be read and verified by the corresponding `readStreamHeader` in the `ObjectInputStream` constructor.

The `writeObject` method is used to serialize an object to the stream. Objects are serialized as follows:

1. If there is data in the block-data buffer, it is written to the stream and the buffer is reset.
2. If the object is null, null is put in the stream and writeObject returns.
3. If the object has already been written to the stream, its handle is written to the stream and writeObject returns. If the object has been already been replaced, the handle for the previously-written replacement object is written to the stream.
4. If the object is a Class, the corresponding ObjectStreamClass is written to the stream, a handle is assigned for the class, and writeObject returns.
5. If the object is an ObjectStreamClass, a descriptor for the class is written to the stream including its name, serialVersionUID, and the list of fields by name and type. A handle is assigned for the descriptor. The annotateClass subclass method is called before `writeObject` returns.
6. If the object is a `java.lang.String,` the string is written in Universal Transfer Format (UTF) format, a handle is assigned to the string, and writeObject returns.
7. If the object is an array, `writeObject` is called recursively to write the `ObjectStreamClass` of the array. The handle for the array is assigned. It is followed by the length of the array. Each element of the array is then written to the stream, after which `writeObject` returns.
8. If enabled by calling `enableReplaceObject`, the `replaceObject` method is called to allow subclasses to substitute an object. If the object is replaced, the mapping from the original object to the replacement is stored for later use in step 3, and steps 2 through 7 are repeated on the new object. If the replacement object is not one of the types covered by steps 2 through 7, processing resumes using the replacement object at step 9.
9. For regular objects, the ObjectStreamClass for the object's class is written by recursively calling writeObject. It will appear in the stream only the first time it is referenced. A handle is assigned for this object.
10. The contents of the object is written to the stream.
    - If the object is Serializable, the highest Serializable class is located. For that class, and each derived class, that class's fields are written. If the class does not have a `writeObject` method, the `defaultWriteObject` method is called to write the nonstatic and nontransient fields to the stream. If the class does have a `writeObject` method, it is called. It may call `defaultWriteObject` to save the state of the object, and then it can write other information to the stream.
    - If the object is `Externalizable`, the writeExternal method of the object is called.
    - If the object is neither Serializable or Externalizable, the NotSerializableException is thrown.

Exceptions may occur during the traversal or may occur in the underlying stream. For any subclass of `ObjectStreamException` the exception is written to the stream using the exception protocol and the stream state is discarded. For other `exceptions`, the stream is aborted and left in an unknown and unusable state.

The `defaultWriteObject` method implements the default serialization mechanism for the current class. This method may be called only from a class's `writeObject` method. The method writes all of the nonstatic and nontransient fields of the current class to the stream. If called from outside the `writeObject` method, the NotActiveException is thrown.

The `reset` method resets the stream state to be the same as if it had just been constructed. Reset will discard the state of any objects already written to the stream. The current point in the stream is marked as reset, so the corresponding ObjectInputStream will reset at the same point. Objects previously written to the stream will not be remembered as already having been written to the stream. They will be written to the stream again. This is useful when the contents of an object or objects must be sent again. Reset may not be called while objects are being serialized. If called inappropriately, an IOException is thrown.

The `annotateClass` method is called while a Class is being serialized, and after the class descriptor has been written to the stream. Subclasses may extend this method and write other information to the stream about the class. This information must be read by the `resolveClass` method in a corresponding `ObjectInputStream` subclass.

The `replaceObject` method is used by trusted subclasses to allow objects within the graph to be replaced or monitored during serialization. Replacing objects must be enabled explicitly by calling `enableReplaceObject` before calling `writeObject` with the first object to be replaced. Once enabled, `replaceObject` is called for each object just prior to serializing the object for the first time. A subclass's implementation may return a substitute object that will be serialized instead of the original. The substitute object must be serializable. All references in the stream to the original object will be replaced by the substitute object.

When objects are being replaced, the subclass must ensure that the substituted object is compatible with every field where the reference will be stored, or that a complementary substitution will be made during deserialization. Objects, whose type is not a subclass of the type of the field or array element, will later abort the deserialization by raising a `ClassCastException` and the reference will not be stored.

The `enableReplaceObject` method is used by trusted subclasses of ObjectOutputStream to enable the substitution of one object for another during serialization. Replacing objects is disabled until `enableReplaceObject` is called with a `true` value. It may thereafter be disabled by setting it to `false`. The previous setting is returned. The `enableReplaceObject` method checks that the stream requesting the replacement can be trusted. Every reference to objects is passed to `replaceObject`. To ensure that the private state of objects is not unintentionally exposed, only trusted streams may use `replaceObject`. Trusted classes are those classes with a class loader equal to null.

The `writeStreamHeader` method writes the magic number and version to the stream. This information must be read by the `readStreamHeader` method of `ObjectInputStream`. Subclasses may need to implement this method to identify the stream's unique format.

The `flush` method is used to empty any buffers being held by the stream and to forward the flush to the underlying stream. The `drain` method may be used by subclassers to empty only the `ObjectOutputStream`'s buffers without forcing the underlying stream to be flushed.

All of the write methods for primitive types encode their values using a DataOutputStream to put them in the standard stream format. The bytes are buffered into block data records so they can be distinguished from the encoding of objects. This buffering allows primitive data to be skipped if necessary for class versioning. It also allows the stream to be parsed without invoking class-specific methods.

# The writeObject Method

For Serializable objects, the `writeObject` method allows a class to control the serialization of its own fields. Here is its signature:

    	private void writeObject(ObjectOutputStream stream)
    		throws IOException;

Each subclass of a Serializable object may define its own writeObject method. If a class does not implement the method, the default serialization provided by defaultWriteObject will be used. When implemented, the class is only responsible for saving its own fields, not those of its supertypes or subtypes.

The class's writeObject method, if implemented, is responsible for saving the state of the class. The `defaultWriteObject` method should be called before writing any optional data that will be needed by the corresponding `readObject` method to restore the state of the object. The responsibility for the format, structure, and versioning of the optional data lies completely with the class.

# The writeExternal Method

Objects implementing `java.io.Externalizable` must implement the `writeExternal` method to save the entire state of the object. It must coordinate with its superclasses to save their state. All of the methods of `ObjectOutput` are available to save the object's primitive typed fields and object fields.

    	public void writeExternal(ObjectOutput stream)
    		throws IOException;

[TOC] [Prev] [Next]

Copyright © 1996, 1997 Sun Microsystems, Inc. All rights reserved.