FileDocCategorySizeDatePackage
ObjectOutputStream.javaAPI DocAndroid 1.5 API86458Wed May 06 22:41:04 BST 2009java.io

ObjectOutputStream

public class ObjectOutputStream extends OutputStream implements ObjectStreamConstants, ObjectOutput
A specialized {@link OutputStream} that is able to write (serialize) Java objects as well as primitive data types (int, byte, char etc.). The data can later be loaded using an ObjectInputStream.
see
ObjectInputStream
see
ObjectOutput
see
Serializable
see
Externalizable
since
Android 1.0

Fields Summary
private int
nestedLevels
private DataOutputStream
output
private boolean
enableReplace
private DataOutputStream
primitiveTypes
private ByteArrayOutputStream
primitiveTypesBuffer
private IdentityHashMap
objectsWritten
private int
currentHandle
private Object
currentObject
private ObjectStreamClass
currentClass
private int
protocolVersion
private StreamCorruptedException
nestedException
private EmulatedFieldsForDumping
currentPutField
private boolean
subclassOverridingImplementation
private IdentityHashMap
writeReplaceCache
Constructors Summary
protected ObjectOutputStream()
Constructs a new {@code ObjectOutputStream}. This default constructor can be used by subclasses that do not want to use the public constructor if it allocates unneeded data.

throws
IOException if an error occurs when creating this stream.
throws
SecurityException if a security manager is installed and it denies subclassing this class.
see
SecurityManager#checkPermission(java.security.Permission)
since
Android 1.0

        super();
        SecurityManager currentManager = System.getSecurityManager();
        if (currentManager != null) {
            currentManager.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
        /*
         * WARNING - we should throw IOException if not called from a subclass
         * according to the JavaDoc. Add the test.
         */
        this.subclassOverridingImplementation = true;
    
public ObjectOutputStream(OutputStream output)
Constructs a new ObjectOutputStream that writes to the OutputStream {@code output}.

param
output the non-null OutputStream to filter writes on.
throws
IOException if an error occurs while writing the object stream header
throws
SecurityException if a security manager is installed and it denies subclassing this class.
since
Android 1.0

        Class<?> implementationClass = getClass();
        Class<?> thisClass = ObjectOutputStream.class;
        if (implementationClass != thisClass) {
            boolean mustCheck = false;
            try {
                Method method = implementationClass.getMethod("putFields", //$NON-NLS-1$
                        ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
                mustCheck = method.getDeclaringClass() != thisClass;
            } catch (NoSuchMethodException e) {
            }
            if (!mustCheck) {
                try {
                    Method method = implementationClass.getMethod(
                            "writeUnshared", //$NON-NLS-1$
                            ObjectStreamClass.UNSHARED_PARAM_TYPES);
                    mustCheck = method.getDeclaringClass() != thisClass;
                } catch (NoSuchMethodException e) {
                }
            }
            if (mustCheck) {
                SecurityManager sm = System.getSecurityManager();
                if (sm != null) {
                    sm
                            .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
                }
            }
        }
        this.output = (output instanceof DataOutputStream) ? (DataOutputStream) output
                : new DataOutputStream(output);
        this.enableReplace = false;
        this.protocolVersion = PROTOCOL_VERSION_2;
        this.subclassOverridingImplementation = false;
        this.writeReplaceCache = new IdentityHashMap<Class<?>, Object>();

        resetState();
        this.nestedException = new StreamCorruptedException();
        // So write...() methods can be used by
        // subclasses during writeStreamHeader()
        primitiveTypes = this.output;
        // Has to be done here according to the specification
        writeStreamHeader();
        primitiveTypes = null;
    
Methods Summary
protected voidannotateClass(java.lang.Class aClass)
Writes optional information for class {@code aClass} to the output stream. This optional data can be read when deserializing the class descriptor (ObjectStreamClass) for this class from an input stream. By default, no extra data is saved.

param
aClass the class to annotate.
throws
IOException if an error occurs while writing to the target stream.
see
ObjectInputStream#resolveClass(ObjectStreamClass)
since
Android 1.0

        // By default no extra info is saved. Subclasses can override
    
protected voidannotateProxyClass(java.lang.Class aClass)
Writes optional information for a proxy class to the target stream. This optional data can be read when deserializing the proxy class from an input stream. By default, no extra data is saved.

param
aClass the proxy class to annotate.
throws
IOException if an error occurs while writing to the target stream.
see
ObjectInputStream#resolveProxyClass(String[])
since
Android 1.0

        // By default no extra info is saved. Subclasses can override
    
private voidcheckWritePrimitiveTypes()
Do the necessary work to see if the receiver can be used to write primitive types like int, char, etc.

        if (primitiveTypes == null) {
            // If we got here we have no Stream previously created
            // WARNING - if the stream does not grow, this code is wrong
            primitiveTypesBuffer = new ByteArrayOutputStream(128);
            primitiveTypes = new DataOutputStream(primitiveTypesBuffer);
        }
    
public voidclose()
Closes this stream. Any buffered data is flushed. This implementation closes the target stream.

throws
IOException if an error occurs while closing this stream.
since
Android 1.0

        // First flush what is needed (primitive data, etc)
        flush();
        output.close();
    
private voidcomputePutField()
Computes the collection of emulated fields that users can manipulate to store a representation different than the one declared by the class of the object being dumped.

see
#writeFields
see
#writeFieldValues(EmulatedFieldsForDumping)

        currentPutField = new EmulatedFieldsForDumping(currentClass);
    
public voiddefaultWriteObject()
Default method to write objects to this stream. Serializable fields defined in the object's class and superclasses are written to the output stream.

throws
IOException if an error occurs while writing to the target stream.
throws
NotActiveException if this method is not called from {@code writeObject()}.
see
ObjectInputStream#defaultReadObject
since
Android 1.0

        // We can't be called from just anywhere. There are rules.
        if (currentObject == null) {
            throw new NotActiveException();
        }
        writeFieldValues(currentObject, currentClass);
    
protected voiddrain()
Writes buffered data to the target stream. This is similar to {@code flush} but the flush is not propagated to the target stream.

throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        if (primitiveTypes == null) {
            return;
        }

        // If we got here we have a Stream previously created
        int offset = 0;
        byte[] written = primitiveTypesBuffer.toByteArray();
        // Normalize the primitive data
        while (offset < written.length) {
            int toWrite = written.length - offset > 1024 ? 1024
                    : written.length - offset;
            if (toWrite < 256) {
                output.writeByte(TC_BLOCKDATA);
                output.writeByte((byte) toWrite);
            } else {
                output.writeByte(TC_BLOCKDATALONG);
                output.writeInt(toWrite);
            }

            // write primitive types we had and the marker of end-of-buffer
            output.write(written, offset, toWrite);
            offset += toWrite;
        }

        // and now we're clean to a state where we can write an object
        primitiveTypes = null;
        primitiveTypesBuffer = null;
    
private java.lang.IntegerdumpCycle(java.lang.Object obj)
Dumps the parameter {@code obj} only if it is {@code null} or an object that has already been dumped previously.

param
obj Object to check if an instance previously dumped by this stream.
return
null if it is an instance which has not been dumped yet (and this method does nothing). Integer, if {@code obj} is an instance which has been dumped already. In this case this method saves the cyclic reference.
throws
IOException If an error occurs attempting to save {@code null} or a cyclic reference.

        // If the object has been saved already, save its handle only
        Integer handle = registeredObjectHandleFor(obj);
        if (handle != null) {
            writeCyclicReference(handle);
            return handle;
        }
        return null;
    
protected booleanenableReplaceObject(boolean enable)
Enables object replacement for this stream. By default this is not enabled. Only trusted subclasses (loaded with system class loader) are allowed to change this status.

param
enable {@code true} to enable object replacement; {@code false} to disable it.
return
the previous setting.
throws
SecurityException if a security manager is installed and it denies enabling object replacement for this stream.
see
#replaceObject
see
ObjectInputStream#enableResolveObject
since
Android 1.0

        if (enable) {
            // The Stream has to be trusted for this feature to be enabled.
            // trusted means the stream's classloader has to be null
            SecurityManager currentManager = System.getSecurityManager();
            if (currentManager != null) {
                currentManager.checkPermission(SUBSTITUTION_PERMISSION);
            }
        }
        boolean originalValue = enableReplace;
        enableReplace = enable;
        return originalValue;
    
public voidflush()
Writes buffered data to the target stream and calls the {@code flush} method of the target stream.

throws
IOException if an error occurs while writing to or flushing the output stream.
since
Android 1.0

        drain();
        output.flush();
    
private static native booleangetFieldBool(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a boolean. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native bytegetFieldByte(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a byte This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native chargetFieldChar(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a char. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native doublegetFieldDouble(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a double. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native floatgetFieldFloat(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a float. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native intgetFieldInt(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be an int. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native longgetFieldLong(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a long. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native java.lang.ObjectgetFieldObj(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, java.lang.String fieldTypeName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be an Object type whose name is {@code fieldTypeName}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
param
fieldTypeName Name of the class that defines the type of this field
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private static native shortgetFieldShort(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName)
Get the value of field named {@code fieldName of object instance}. The field is declared by class {@code declaringClass}. The field is supposed to be a short. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except by the use of a native method like this one.

param
instance Object whose field value we want to fetch
param
declaringClass The class that declares the field
param
fieldName Name of the field we want to fetch
return
the value of the field
throws
NoSuchFieldError If the field does not exist.

private intnextHandle()
Return the next {@code int} handle to be used to indicate cyclic references being saved to the stream.

return
int, the next handle to represent the next cyclic reference

        return this.currentHandle++;
    
public java.io.ObjectOutputStream$PutFieldputFields()
Gets this stream's {@code PutField} object. This object provides access to the persistent fields that are eventually written to the output stream. It is used to transfer the values from the fields of the object that is currently being written to the persistent fields.

return
the PutField object from which persistent fields can be accessed by name.
throws
IOException if an I/O error occurs.
throws
NotActiveException if this method is not called from {@code writeObject()}.
see
ObjectInputStream#defaultReadObject
since
Android 1.0

        // We can't be called from just anywhere. There are rules.
        if (currentObject == null) {
            throw new NotActiveException();
        }
        if (currentPutField == null) {
            computePutField();
        }
        return currentPutField;
    
private java.lang.IntegerregisterObjectWritten(java.lang.Object obj)
Assume object {@code obj} has not been dumped yet, and assign a handle to it

param
obj Non-null object being dumped.
return
the handle that this object is being assigned.
see
#nextHandle

        Integer handle = Integer.valueOf(nextHandle());
        registerObjectWritten(obj, handle);
        return handle;
    
private voidregisterObjectWritten(java.lang.Object obj, java.lang.Integer handle)
Assume object {@code obj} has not been dumped yet, and assign a handle to it, {@code handle}.

param
obj Non-null object being dumped.
param
handle An Integer, the handle to this object
see
#nextHandle

        objectsWritten.put(obj, handle);
    
private java.lang.IntegerregisteredObjectHandleFor(java.lang.Object obj)
Return the {@code Integer} handle used to tag object {@code obj} as an instance that has been dumped already. Return {@code null} if object {@code obj} has not been saved yet.

param
obj the object
return
null if object {@code obj} has not been saved yet. Integer The handle that this object was assigned when it was saved.

        return objectsWritten.get(obj);
    
private voidremoveUnsharedReference(java.lang.Object obj, java.lang.Integer previousHandle)
Remove the unshared object from the table, and restore any previous handle.

param
obj Non-null object being dumped.
param
previousHandle The handle of the previous identical object dumped

        if (previousHandle != null) {
            registerObjectWritten(obj, previousHandle);
        } else {
            objectsWritten.remove(obj);
        }
    
protected java.lang.ObjectreplaceObject(java.lang.Object object)
Allows trusted subclasses to substitute the specified original {@code object} with a new object. Object substitution has to be activated first with calling {@code enableReplaceObject(true)}. This implementation just returns {@code object}.

param
object the original object for which a replacement may be defined.
return
the replacement object for {@code object}.
throws
IOException if any I/O error occurs while creating the replacement object.
see
#enableReplaceObject
see
ObjectInputStream#enableResolveObject
see
ObjectInputStream#resolveObject
since
Android 1.0

        // By default no object replacement. Subclasses can override
        return object;
    
public voidreset()
Resets the state of this stream. A marker is written to the stream, so that the corresponding input stream will also perform a reset at the same point. Objects previously written are no longer remembered, so they will be written again (instead of a cyclical reference) if found in the object graph.

throws
IOException if {@code reset()} is called during the serialization of an object.
since
Android 1.0

        // First we flush what we have
        drain();
        /*
         * And dump a reset marker, so that the ObjectInputStream can reset
         * itself at the same point
         */
        output.writeByte(TC_RESET);
        // Now we reset ourselves
        resetState();
    
private voidresetSeenObjects()
Reset the collection of objects already dumped by the receiver. If the objects are found again in the object graph, the receiver will dump them again, instead of a handle (cyclic reference).

        objectsWritten = new IdentityHashMap<Object, Integer>();
        currentHandle = baseWireHandle;
    
private voidresetState()
Reset the receiver. The collection of objects already dumped by the receiver is reset, and internal structures are also reset so that the receiver knows it is in a fresh clean state.

        resetSeenObjects();
        nestedLevels = 0;
    
public voiduseProtocolVersion(int version)
Sets the specified protocol version to be used by this stream.

param
version the protocol version to be used. Use a {@code PROTOCOL_VERSION_x} constant from {@code java.io.ObjectStreamConstants}.
throws
IllegalArgumentException if an invalid {@code version} is specified.
throws
IOException if an I/O error occurs.
see
ObjectStreamConstants#PROTOCOL_VERSION_1
see
ObjectStreamConstants#PROTOCOL_VERSION_2
since
Android 1.0

        if (version != ObjectStreamConstants.PROTOCOL_VERSION_1
                && version != ObjectStreamConstants.PROTOCOL_VERSION_2) {
            throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg
                    .getString("K00b3", version)); //$NON-NLS-1$
        }
        protocolVersion = version;
    
public voidwrite(byte[] buffer)
Writes the entire contents of the byte array {@code buffer} to the output stream. Blocks until all bytes are written.

param
buffer the buffer to write.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.write(buffer);
    
public voidwrite(byte[] buffer, int offset, int length)
Writes {@code count} bytes from the byte array {@code buffer} starting at offset {@code index} to the target stream. Blocks until all bytes are written.

param
buffer the buffer to write.
param
offset the index of the first byte in {@code buffer} to write.
param
length the number of bytes from {@code buffer} to write to the output stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.write(buffer, offset, length);
    
public voidwrite(int value)
Writes a single byte to the target stream. Only the least significant byte of the integer {@code value} is written to the stream. Blocks until the byte is actually written.

param
value the byte to write.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.write(value);
    
public voidwriteBoolean(boolean value)
Writes a boolean to the target stream.

param
value the boolean value to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeBoolean(value);
    
public voidwriteByte(int value)
Writes a byte (8 bit) to the target stream.

param
value the byte to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeByte(value);
    
public voidwriteBytes(java.lang.String value)
Writes the string {@code value} as a sequence of bytes to the target stream. Only the least significant byte of each character in the string is written.

param
value the string to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeBytes(value);
    
public voidwriteChar(int value)
Writes a character (16 bit) to the target stream.

param
value the character to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeChar(value);
    
public voidwriteChars(java.lang.String value)
Writes the string {@code value} as a sequence of characters to the target stream.

param
value the string to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeChars(value);
    
private java.lang.IntegerwriteClassDesc(java.io.ObjectStreamClass classDesc, boolean unshared)
Write a class descriptor {@code classDesc} (an {@code ObjectStreamClass}) to the stream.

param
classDesc The class descriptor (an {@code ObjectStreamClass}) to be dumped
param
unshared Write the object unshared
return
the handle assigned to the class descriptor
throws
IOException If an IO exception happened when writing the class descriptor.

        if (classDesc == null) {
            writeNull();
            return null;
        }
        Integer handle = null;
        if (!unshared) {
            handle = dumpCycle(classDesc);
        }
        if (handle == null) {
            Class<?> classToWrite = classDesc.forClass();
            Integer previousHandle = objectsWritten.get(classDesc);
            // If we got here, it is a new (non-null) classDesc that will have
            // to be registered as well
            handle = registerObjectWritten(classDesc);

            if (Proxy.isProxyClass(classToWrite)) {
                output.writeByte(TC_PROXYCLASSDESC);
                Class<?>[] interfaces = classToWrite.getInterfaces();
                output.writeInt(interfaces.length);
                for (int i = 0; i < interfaces.length; i++) {
                    output.writeUTF(interfaces[i].getName());
                }
                annotateProxyClass(classToWrite);
                output.writeByte(TC_ENDBLOCKDATA);
                writeClassDescForClass(Proxy.class);
                if (unshared) {
                    // remove reference to unshared object
                    removeUnsharedReference(classDesc, previousHandle);
                }
                return handle;
            }

            output.writeByte(TC_CLASSDESC);
            if (protocolVersion == PROTOCOL_VERSION_1) {
                writeNewClassDesc(classDesc);
            } else {
                // So write...() methods can be used by
                // subclasses during writeClassDescriptor()
                primitiveTypes = output;
                writeClassDescriptor(classDesc);
                primitiveTypes = null;
            }
            // Extra class info (optional)
            annotateClass(classToWrite);
            drain(); // flush primitive types in the annotation
            output.writeByte(TC_ENDBLOCKDATA);
            writeClassDesc(classDesc.getSuperclass(), unshared);
            if (unshared) {
                // remove reference to unshared object
                removeUnsharedReference(classDesc, previousHandle);
            }
        }
        return handle;
    
private java.lang.IntegerwriteClassDescForClass(java.lang.Class objClass)
Writes a class descriptor (an {@code ObjectStreamClass}) that corresponds to the {@code java.lang.Class objClass} to the stream.

param
objClass The class for which a class descriptor (an {@code ObjectStreamClass}) will be dumped.
return
the handle assigned to the class descriptor
throws
IOException If an IO exception happened when writing the class descriptor.

        return writeClassDesc(ObjectStreamClass.lookup(objClass), false);
    
protected voidwriteClassDescriptor(java.io.ObjectStreamClass classDesc)
Writes a class descriptor to the target stream.

param
classDesc the class descriptor to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        writeNewClassDesc(classDesc);
    
private voidwriteCyclicReference(java.lang.Integer handle)
Writes a handle representing a cyclic reference (object previously dumped).

param
handle The Integer handle that represents an object previously seen
throws
IOException If an IO exception happened when writing the cyclic reference.

        output.writeByte(TC_REFERENCE);
        output.writeInt(handle.intValue());
    
public voidwriteDouble(double value)
Writes a double (64 bit) to the target stream.

param
value the double to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeDouble(value);
    
private java.io.ObjectStreamClasswriteEnumDesc(java.lang.Class theClass, boolean unshared)

        // write classDesc, classDesc for enum is different
        ObjectStreamClass classDesc = ObjectStreamClass.lookup(theClass);
        // set flag for enum, the flag is (SC_SERIALIZABLE | SC_ENUM)
        classDesc.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
        Integer previousHandle = objectsWritten.get(classDesc);
        Integer handle = null;
        if (!unshared) {
            handle = dumpCycle(classDesc);
        }
        if (handle == null) {
            Class<?> classToWrite = classDesc.forClass();
            // If we got here, it is a new (non-null) classDesc that will have
            // to be registered as well
            registerObjectWritten(classDesc);

            output.writeByte(TC_CLASSDESC);
            if (protocolVersion == PROTOCOL_VERSION_1) {
                writeNewClassDesc(classDesc);
            } else {
                // So write...() methods can be used by
                // subclasses during writeClassDescriptor()
                primitiveTypes = output;
                writeClassDescriptor(classDesc);
                primitiveTypes = null;
            }
            // Extra class info (optional)
            annotateClass(classToWrite);
            drain(); // flush primitive types in the annotation
            output.writeByte(TC_ENDBLOCKDATA);
            // write super class
            ObjectStreamClass superClass = classDesc.getSuperclass();
            if (null != superClass) {
                // super class is also enum
                superClass.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
                writeEnumDesc(superClass.forClass(), unshared);
            } else {
                output.writeByte(TC_NULL);
            }
            if (unshared) {
                // remove reference to unshared object
                removeUnsharedReference(classDesc, previousHandle);
            }
        }
        return classDesc;
    
private voidwriteFieldDescriptors(java.io.ObjectStreamClass classDesc, boolean externalizable)
Writes a collection of field descriptors (name, type name, etc) for the class descriptor {@code classDesc} (an {@code ObjectStreamClass})

param
classDesc The class descriptor (an {@code ObjectStreamClass}) for which to write field information
param
externalizable true if the descriptors are externalizable
throws
IOException If an IO exception happened when writing the field descriptors.
see
#writeObject(Object)

        Class<?> loadedClass = classDesc.forClass();
        ObjectStreamField[] fields = null;
        int fieldCount = 0;

        // The fields of String are not needed since Strings are treated as
        // primitive types
        if (!externalizable && loadedClass != ObjectStreamClass.STRINGCLASS) {
            fields = classDesc.fields();
            fieldCount = fields.length;
        }

        // Field count
        output.writeShort(fieldCount);
        // Field names
        for (int i = 0; i < fieldCount; i++) {
            ObjectStreamField f = fields[i];
            output.writeByte(f.getTypeCode());
            output.writeUTF(f.getName());
            if (!f.isPrimitive()) {
                writeObject(f.getTypeString());
            }
        }
    
private voidwriteFieldValues(EmulatedFieldsForDumping emulatedFields)
Writes a collection of field values for the emulated fields {@code emulatedFields}

param
emulatedFields an {@code EmulatedFieldsForDumping}, concrete subclass of {@code PutField}
throws
IOException If an IO exception happened when writing the field values.
see
#writeFields
see
#writeObject(Object)

        EmulatedFields accessibleSimulatedFields = emulatedFields
                .emulatedFields(); // Access internal fields which we can
        // set/get. Users can't do this.
        EmulatedFields.ObjectSlot[] slots = accessibleSimulatedFields.slots();
        for (int i = 0; i < slots.length; i++) {
            EmulatedFields.ObjectSlot slot = slots[i];
            Object fieldValue = slot.getFieldValue();
            Class<?> type = slot.getField().getType();
            // WARNING - default values exist for each primitive type
            if (type == Integer.TYPE) {
                output.writeInt(fieldValue != null ? ((Integer) fieldValue)
                        .intValue() : 0);
            } else if (type == Byte.TYPE) {
                output.writeByte(fieldValue != null ? ((Byte) fieldValue)
                        .byteValue() : (byte) 0);
            } else if (type == Character.TYPE) {
                output.writeChar(fieldValue != null ? ((Character) fieldValue)
                        .charValue() : (char) 0);
            } else if (type == Short.TYPE) {
                output.writeShort(fieldValue != null ? ((Short) fieldValue)
                        .shortValue() : (short) 0);
            } else if (type == Boolean.TYPE) {
                output.writeBoolean(fieldValue != null ? ((Boolean) fieldValue)
                        .booleanValue() : false);
            } else if (type == Long.TYPE) {
                output.writeLong(fieldValue != null ? ((Long) fieldValue)
                        .longValue() : (long) 0);
            } else if (type == Float.TYPE) {
                output.writeFloat(fieldValue != null ? ((Float) fieldValue)
                        .floatValue() : (float) 0);
            } else if (type == Double.TYPE) {
                output.writeDouble(fieldValue != null ? ((Double) fieldValue)
                        .doubleValue() : (double) 0);
            } else {
                // Either array or Object
                writeObject(fieldValue);
            }
        }
    
private voidwriteFieldValues(java.lang.Object obj, java.io.ObjectStreamClass classDesc)
Writes a collection of field values for the fields described by class descriptor {@code classDesc} (an {@code ObjectStreamClass}). This is the default mechanism, when emulated fields (an {@code PutField}) are not used. Actual values to dump are fetched directly from object {@code obj}.

param
obj Instance from which to fetch field values to dump.
param
classDesc A class descriptor (an {@code ObjectStreamClass}) defining which fields should be dumped.
throws
IOException If an IO exception happened when writing the field values.
see
#writeObject(Object)

        ObjectStreamField[] fields = classDesc.fields();
        Class<?> declaringClass = classDesc.forClass();
        for (int i = 0; i < fields.length; i++) {
            try {
                // Code duplication starts, just because Java is typed
                ObjectStreamField fieldDesc = fields[i];
                if (fieldDesc.isPrimitive()) {
                    switch (fieldDesc.getTypeCode()) {
                        case 'B":
                            output.writeByte(getFieldByte(obj, declaringClass,
                                    fieldDesc.getName()));
                            break;
                        case 'C":
                            output.writeChar(getFieldChar(obj, declaringClass,
                                    fieldDesc.getName()));
                            break;
                        case 'D":
                            output.writeDouble(getFieldDouble(obj,
                                    declaringClass, fieldDesc.getName()));
                            break;
                        case 'F":
                            output.writeFloat(getFieldFloat(obj,
                                    declaringClass, fieldDesc.getName()));
                            break;
                        case 'I":
                            output.writeInt(getFieldInt(obj, declaringClass,
                                    fieldDesc.getName()));
                            break;
                        case 'J":
                            output.writeLong(getFieldLong(obj, declaringClass,
                                    fieldDesc.getName()));
                            break;
                        case 'S":
                            output.writeShort(getFieldShort(obj,
                                    declaringClass, fieldDesc.getName()));
                            break;
                        case 'Z":
                            output.writeBoolean(getFieldBool(obj,
                                    declaringClass, fieldDesc.getName()));
                            break;
                        default:
                            throw new IOException(
                                    org.apache.harmony.luni.util.Msg.getString(
                                            "K00d5", fieldDesc.getTypeCode())); //$NON-NLS-1$
                    }
                } else {
                    // Object type (array included).
                    Object field = getFieldObj(obj, declaringClass, fieldDesc
                            .getName(), fieldDesc.getTypeString());
                    if (fieldDesc.isUnshared()) {
                        writeUnshared(field);
                    } else {
                        writeObject(field);
                    }
                }
            } catch (NoSuchFieldError nsf) {
                // The user defined serialPersistentFields but did not provide
                // the glue to transfer values,
                // (in writeObject) so we end up using the default mechanism and
                // fail to set the emulated field
                throw new InvalidClassException(classDesc.getName());
            }
        }
    
public voidwriteFields()
Writes the fields of the object currently being written to the target stream. The field values are buffered in the currently active {@code PutField} object, which can be accessed by calling {@code putFields()}.

throws
IOException if an error occurs while writing to the target stream.
throws
NotActiveException if there are no fields to write to the target stream.
see
#putFields
since
Android 1.0

        // Has to have fields to write
        if (currentPutField == null) {
            throw new NotActiveException();
        }
        writeFieldValues(currentPutField);
    
public voidwriteFloat(float value)
Writes a float (32 bit) to the target stream.

param
value the float to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeFloat(value);
    
private voidwriteHierarchy(java.lang.Object object, java.io.ObjectStreamClass classDesc)
Walks the hierarchy of classes described by class descriptor {@code classDesc} and writes the field values corresponding to fields declared by the corresponding class descriptor. The instance to fetch field values from is {@code object}. If the class (corresponding to class descriptor {@code classDesc}) defines private instance method {@code writeObject} it will be used to dump field values.

param
object Instance from which to fetch field values to dump.
param
classDesc A class descriptor (an {@code ObjectStreamClass}) defining which fields should be dumped.
throws
IOException If an IO exception happened when writing the field values in the hierarchy.
throws
NotActiveException If the given object is not active
see
#defaultWriteObject
see
#writeObject(Object)

        // We can't be called from just anywhere. There are rules.
        if (object == null) {
            throw new NotActiveException();
        }

        // Fields are written from class closest to Object to leaf class
        // (down the chain)
        if (classDesc.getSuperclass() != null) {
            // first
            writeHierarchy(object, classDesc.getSuperclass());
        }

        // Have to do this before calling defaultWriteObject or anything
        // that calls defaultWriteObject
        currentObject = object;
        currentClass = classDesc;

        // See if the object has a writeObject method. If so, run it
        boolean executed = false;
        Class<?> targetClass = classDesc.forClass();
        try {
            final Method method = ObjectStreamClass
                    .getPrivateWriteObjectMethod(targetClass);
            if (method != null) {
                // We have to be able to fetch its value, even if it is
                // private
                AccessController.doPrivileged(new PriviAction<Object>(method));
                try {
                    method.invoke(object, new Object[] { this });
                    executed = true;
                } catch (InvocationTargetException e) {
                    Throwable ex = e.getTargetException();
                    if (ex instanceof RuntimeException) {
                        throw (RuntimeException) ex;
                    } else if (ex instanceof Error) {
                        throw (Error) ex;
                    }
                    throw (IOException) ex;
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e.toString());
                }
            }

            if (executed) {
                drain();
                output.writeByte(TC_ENDBLOCKDATA);
            } else {
                // If the object did not have a writeMethod, call
                // defaultWriteObject
                defaultWriteObject();
            }
        } finally {
            // Cleanup, needs to run always so that we can later detect
            // invalid calls to defaultWriteObject
            currentObject = null;
            currentClass = null;
            currentPutField = null;
        }
    
public voidwriteInt(int value)
Writes an integer (32 bit) to the target stream.

param
value the integer to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeInt(value);
    
public voidwriteLong(long value)
Writes a long (64 bit) to the target stream.

param
value the long to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeLong(value);
    
private java.lang.IntegerwriteNewArray(java.lang.Object array, java.lang.Class arrayClass, java.lang.Class componentType, boolean unshared)
Write array {@code array} of class {@code arrayClass} with component type {@code componentType} into the receiver. It is assumed the array has not been dumped yet. Return an {@code Integer} that represents the handle for this object (array) which is dumped here.

param
array The array object to dump
param
arrayClass A {@code java.lang.Class} representing the class of the array
param
componentType A {@code java.lang.Class} representing the array component type
return
the handle assigned to the array
throws
IOException If an IO exception happened when writing the array.

        output.writeByte(TC_ARRAY);
        writeClassDescForClass(arrayClass);

        Integer previousHandle = objectsWritten.get(array);
        Integer handle = registerObjectWritten(array);
        if (unshared) {
            // remove reference to unshared object
            removeUnsharedReference(array, previousHandle);
        }

        // Now we have code duplication just because Java is typed. We have to
        // write N elements and assign to array positions, but we must typecast
        // the array first, and also call different methods depending on the
        // elements.

        if (componentType.isPrimitive()) {
            if (componentType == Integer.TYPE) {
                int[] intArray = (int[]) array;
                output.writeInt(intArray.length);
                for (int i = 0; i < intArray.length; i++) {
                    output.writeInt(intArray[i]);
                }
            } else if (componentType == Byte.TYPE) {
                byte[] byteArray = (byte[]) array;
                output.writeInt(byteArray.length);
                output.write(byteArray, 0, byteArray.length);
            } else if (componentType == Character.TYPE) {
                char[] charArray = (char[]) array;
                output.writeInt(charArray.length);
                for (int i = 0; i < charArray.length; i++) {
                    output.writeChar(charArray[i]);
                }
            } else if (componentType == Short.TYPE) {
                short[] shortArray = (short[]) array;
                output.writeInt(shortArray.length);
                for (int i = 0; i < shortArray.length; i++) {
                    output.writeShort(shortArray[i]);
                }
            } else if (componentType == Boolean.TYPE) {
                boolean[] booleanArray = (boolean[]) array;
                output.writeInt(booleanArray.length);
                for (int i = 0; i < booleanArray.length; i++) {
                    output.writeBoolean(booleanArray[i]);
                }
            } else if (componentType == Long.TYPE) {
                long[] longArray = (long[]) array;
                output.writeInt(longArray.length);
                for (int i = 0; i < longArray.length; i++) {
                    output.writeLong(longArray[i]);
                }
            } else if (componentType == Float.TYPE) {
                float[] floatArray = (float[]) array;
                output.writeInt(floatArray.length);
                for (int i = 0; i < floatArray.length; i++) {
                    output.writeFloat(floatArray[i]);
                }
            } else if (componentType == Double.TYPE) {
                double[] doubleArray = (double[]) array;
                output.writeInt(doubleArray.length);
                for (int i = 0; i < doubleArray.length; i++) {
                    output.writeDouble(doubleArray[i]);
                }
            } else {
                throw new InvalidClassException(
                        org.apache.harmony.luni.util.Msg.getString(
                                "K00d7", arrayClass.getName())); //$NON-NLS-1$
            }
        } else {
            // Array of Objects
            Object[] objectArray = (Object[]) array;
            output.writeInt(objectArray.length);
            for (int i = 0; i < objectArray.length; i++) {
                writeObject(objectArray[i]);
            }
        }
        return handle;
    
private java.lang.IntegerwriteNewClass(java.lang.Class object, boolean unshared)
Write class {@code object} into the receiver. It is assumed the class has not been dumped yet. Classes are not really dumped, but a class descriptor ({@code ObjectStreamClass}) that corresponds to them. Return an {@code Integer} that represents the handle for this object (class) which is dumped here.

param
object The {@code java.lang.Class} object to dump
return
the handle assigned to the class being dumped
throws
IOException If an IO exception happened when writing the class.

        output.writeByte(TC_CLASS);

        // Instances of java.lang.Class are always Serializable, even if their
        // instances aren't (e.g. java.lang.Object.class).
        // We cannot call lookup because it returns null if the parameter
        // represents instances that cannot be serialized, and that is not what
        // we want.

        // The handle for the classDesc is NOT the handle for the class object
        // being dumped. We must allocate a new handle and return it.
        if (object.isEnum()) {
            writeEnumDesc(object, unshared);
        } else {
            writeClassDesc(ObjectStreamClass.lookupStreamClass(object),
                    unshared);
        }

        Integer previousHandle = objectsWritten.get(object);
        Integer handle = registerObjectWritten(object);
        if (unshared) {
            // remove reference to unshared object
            removeUnsharedReference(object, previousHandle);
        }

        return handle;
    
private voidwriteNewClassDesc(java.io.ObjectStreamClass classDesc)
Write class descriptor {@code classDesc} into the receiver. It is assumed the class descriptor has not been dumped yet. The class descriptors for the superclass chain will be dumped as well. Return an {@code Integer} that represents the handle for this object (class descriptor) which is dumped here.

param
classDesc The {@code ObjectStreamClass} object to dump
throws
IOException If an IO exception happened when writing the class descriptor.

        output.writeUTF(classDesc.getName());
        output.writeLong(classDesc.getSerialVersionUID());
        byte flags = classDesc.getFlags();
        boolean externalizable = false;
        externalizable = ObjectStreamClass.isExternalizable(classDesc
                .forClass());
        if (protocolVersion != PROTOCOL_VERSION_1) {
            // Change for 1.2. Objects can be saved in old format
            // (PROTOCOL_VERSION_1) or in the 1.2 format (PROTOCOL_VERSION_2).
            // Nested "if" check to optimize checking. Second check is more
            // expensive.
            if (externalizable) {
                flags |= SC_BLOCK_DATA;
            }
        }
        output.writeByte(flags);
        if ((SC_ENUM | SC_SERIALIZABLE) != classDesc.getFlags()) {
            writeFieldDescriptors(classDesc, externalizable);
        } else {
            // enum write no fields
            output.writeShort(0);
        }
    
private java.lang.IntegerwriteNewEnum(java.lang.Object object, java.lang.Class theClass, boolean unshared)

        // write new Enum
        EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
        // null it, to make sure one will be computed if needed
        currentPutField = null;

        output.writeByte(TC_ENUM);
        while (theClass != null && !theClass.isEnum()) {
            // write enum only
            theClass = theClass.getSuperclass();
        }
        ObjectStreamClass classDesc = writeEnumDesc(theClass, unshared);

        Integer previousHandle = objectsWritten.get(object);
        Integer handle = registerObjectWritten(object);

        ObjectStreamField[] fields = classDesc.getSuperclass().fields();
        Class<?> declaringClass = classDesc.getSuperclass().forClass();
        // Only write field "name" for enum class, which is the second field of
        // enum, that is fields[1]. Ignore all non-fields and fields.length < 2
        if (null != fields && fields.length > 1) {
            String str = (String) getFieldObj(object, declaringClass, fields[1]
                    .getName(), fields[1].getTypeString());
            Integer strhandle = null;
            if (!unshared) {
                strhandle = dumpCycle(str);
            }
            if (null == strhandle) {
                writeNewString(str, unshared);
            }
        }

        if (unshared) {
            // remove reference to unshared object
            removeUnsharedReference(object, previousHandle);
        }
        currentPutField = originalCurrentPutField;
        return handle;
    
private voidwriteNewException(java.lang.Exception ex)
Write exception {@code ex} into the receiver. It is assumed the exception has not been dumped yet. Return an {@code Integer} that represents the handle for this object (exception) which is dumped here. This is used to dump the exception instance that happened (if any) when dumping the original object graph. The set of seen objects will be reset just before and just after dumping this exception object. When exceptions are found normally in the object graph, they are dumped as a regular object, and not by this method. In that case, the set of "known objects" is not reset.

param
ex Exception object to dump
throws
IOException If an IO exception happened when writing the exception object.

        output.writeByte(TC_EXCEPTION);
        resetSeenObjects();
        writeObjectInternal(ex, false, false, false); // No replacements
        resetSeenObjects();
    
private java.lang.IntegerwriteNewObject(java.lang.Object object, java.lang.Class theClass, boolean unshared)
Write object {@code object} of class {@code theClass} into the receiver. It is assumed the object has not been dumped yet. Return an {@code Integer} that represents the handle for this object which is dumped here. If the object implements {@code Externalizable} its {@code writeExternal} is called. Otherwise, all fields described by the class hierarchy is dumped. Each class can define how its declared instance fields are dumped by defining a private method {@code writeObject}

param
object The object to dump
param
theClass A {@code java.lang.Class} representing the class of the object
param
unshared Write the object unshared
return
the handle assigned to the object
throws
IOException If an IO exception happened when writing the object.

        // Not String, not null, not array, not cyclic reference

        EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
        currentPutField = null; // null it, to make sure one will be computed if
        // needed

        boolean externalizable = ObjectStreamClass.isExternalizable(theClass);
        boolean serializable = ObjectStreamClass.isSerializable(theClass);
        if (!externalizable && !serializable) {
            // Object is neither externalizable nor serializable. Error
            throw new NotSerializableException(theClass.getName());
        }

        // Either serializable or externalizable, now we can save info
        output.writeByte(TC_OBJECT);
        writeClassDescForClass(theClass);
        Integer previousHandle = objectsWritten.get(object);
        Integer handle = registerObjectWritten(object);

        // This is how we know what to do in defaultWriteObject. And it is also
        // used by defaultWriteObject to check if it was called from an invalid
        // place.
        // It allows writeExternal to call defaultWriteObject and have it work.
        currentObject = object;
        currentClass = ObjectStreamClass.lookup(theClass);
        try {
            if (externalizable) {
                boolean noBlockData = protocolVersion == PROTOCOL_VERSION_1;
                if (noBlockData) {
                    primitiveTypes = output;
                }
                // Object is externalizable, just call its own method
                ((Externalizable) object).writeExternal(this);
                if (noBlockData) {
                    primitiveTypes = null;
                } else {
                    // Similar to the code in writeHierarchy when object
                    // implements writeObject.
                    // Any primitive data has to be flushed and a tag must be
                    // written
                    drain();
                    output.writeByte(TC_ENDBLOCKDATA);
                }
            } else { // If it got here, it has to be Serializable
                // Object is serializable. Walk the class chain writing the
                // fields
                writeHierarchy(object, currentClass);
            }
        } finally {
            // Cleanup, needs to run always so that we can later detect invalid
            // calls to defaultWriteObject
            if (unshared) {
                // remove reference to unshared object
                removeUnsharedReference(object, previousHandle);
            }
            currentObject = null;
            currentClass = null;
            currentPutField = originalCurrentPutField;
        }

        return handle;
    
private java.lang.IntegerwriteNewString(java.lang.String object, boolean unshared)
Write String {@code object} into the receiver. It is assumed the String has not been dumped yet. Return an {@code Integer} that represents the handle for this object (String) which is dumped here. Strings are saved encoded with {@link DataInput modified UTF-8}.

param
object the string to dump.
return
the handle assigned to the String being dumped
throws
IOException If an IO exception happened when writing the String.

        long count = output.countUTFBytes(object);
        if (count <= 0xffff) {
            output.writeByte(TC_STRING);
            output.writeShort((short) count);
        } else {
            output.writeByte(TC_LONGSTRING);
            output.writeLong(count);
        }
        output.writeUTFBytes(object, count);

        Integer previousHandle = objectsWritten.get(object);
        Integer handle = registerObjectWritten(object);
        if (unshared) {
            // remove reference to unshared object
            removeUnsharedReference(object, previousHandle);
        }
        return handle;
    
private voidwriteNull()
Write a special tag that indicates the value {@code null} into the receiver.

throws
IOException If an IO exception happened when writing the tag for {@code null}.

        output.writeByte(TC_NULL);
    
public final voidwriteObject(java.lang.Object object)
Writes an object to the target stream.

param
object the object to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
see
ObjectInputStream#readObject()
since
Android 1.0

        writeObject(object, false);
    
private voidwriteObject(java.lang.Object object, boolean unshared)

        boolean setOutput = (primitiveTypes == output);
        if (setOutput) {
            primitiveTypes = null;
        }
        // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
        // behavior overriding.
        if (subclassOverridingImplementation && !unshared) {
            writeObjectOverride(object);
        } else {

            try {
                // First we need to flush primitive types if they were written
                drain();
                // Actual work, and class-based replacement should be computed
                // if needed.
                writeObjectInternal(object, unshared, true, true);
                if (setOutput) {
                    primitiveTypes = output;
                }
            } catch (IOException ioEx1) {
                // This will make it pass through until the top caller. It also
                // lets it pass through the nested exception.
                if (nestedLevels == 0 && ioEx1 != nestedException) {
                    try {
                        writeNewException(ioEx1);
                    } catch (IOException ioEx2) {
                        nestedException.fillInStackTrace();
                        throw nestedException;
                    }
                }
                throw ioEx1; // and then we propagate the original exception
            }
        }
    
private java.lang.IntegerwriteObjectInternal(java.lang.Object object, boolean unshared, boolean computeClassBasedReplacement, boolean computeStreamReplacement)
Write object {@code object} into the receiver's underlying stream.

param
object The object to write
param
unshared Write the object unshared
param
computeClassBasedReplacement A boolean indicating if class-based replacement should be computed (if supported) for the object.
param
computeStreamReplacement A boolean indicating if stream-based replacement should be computed (if supported) for the object.
return
the handle assigned to the final object being dumped
throws
IOException If an IO exception happened when writing the object
see
ObjectInputStream#readObject()


        if (object == null) {
            writeNull();
            return null;
        }
        Integer handle = null;
        if (!unshared) {
            handle = dumpCycle(object);
            if (handle != null) {
                return handle; // cyclic reference
            }
        }

        // Non-null object, first time seen...
        Class<?> objClass = object.getClass();
        nestedLevels++;
        try {

            if (!(enableReplace && computeStreamReplacement)) {
                // Is it a Class ?
                if (objClass == ObjectStreamClass.CLASSCLASS) {
                    return writeNewClass((Class<?>) object, unshared);
                }
                // Is it an ObjectStreamClass ?
                if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
                    return writeClassDesc((ObjectStreamClass) object, unshared);
                }
            }

            if (ObjectStreamClass.isSerializable(object.getClass())
                    && computeClassBasedReplacement) {
                Object writeReplaceMethod = writeReplaceCache.get(objClass);
                if (writeReplaceMethod != this) {
                    if (writeReplaceMethod == null) {
                        final Method writeReplace = ObjectStreamClass
                                .methodWriteReplace(objClass);
                        if (writeReplace == null) {
                            writeReplaceCache.put(objClass, this);
                            writeReplaceMethod = null;
                        } else {
                            // Has replacement method
                            AccessController
                                    .doPrivileged(new PriviAction<Object>(
                                            writeReplace));
                            writeReplaceCache.put(objClass, writeReplace);
                            writeReplaceMethod = writeReplace;
                        }
                    }
                    if (writeReplaceMethod != null) {
                        Object classBasedReplacement;
                        try {
                            classBasedReplacement = ((Method) writeReplaceMethod)
                                    .invoke(object, (Object[]) null);
                        } catch (IllegalAccessException iae) {
                            classBasedReplacement = object;
                        } catch (InvocationTargetException ite) {
                            // WARNING - Not sure this is the right thing to do
                            // if we can't run the method
                            Throwable target = ite.getTargetException();
                            if (target instanceof ObjectStreamException) {
                                throw (ObjectStreamException) target;
                            } else if (target instanceof Error) {
                                throw (Error) target;
                            } else {
                                throw (RuntimeException) target;
                            }
                        }
                        if (classBasedReplacement != object) {
                            // All over, class-based replacement off this time.
                            Integer replacementHandle = writeObjectInternal(
                                    classBasedReplacement, false, false,
                                    computeStreamReplacement);
                            // Make the original object also map to the same
                            // handle.
                            if (replacementHandle != null) {
                                registerObjectWritten(object, replacementHandle);
                            }
                            return replacementHandle;
                        }
                    }
                }
            }

            // We get here either if class-based replacement was not needed or
            // if it was needed but produced the same object or if it could not
            // be computed.
            if (enableReplace && computeStreamReplacement) {
                // Now we compute the stream-defined replacement.
                Object streamReplacement = replaceObject(object);
                if (streamReplacement != object) {
                    // All over, class-based replacement off this time.
                    Integer replacementHandle = writeObjectInternal(
                            streamReplacement, false,
                            computeClassBasedReplacement, false);
                    // Make the original object also map to the same handle.
                    if (replacementHandle != null) {
                        registerObjectWritten(object, replacementHandle);
                    }
                    return replacementHandle;
                }
            }

            // We get here if stream-based replacement produced the same object

            // Is it a Class ?
            if (objClass == ObjectStreamClass.CLASSCLASS) {
                return writeNewClass((Class<?>) object, unshared);
            }

            // Is it an ObjectStreamClass ?
            if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
                return writeClassDesc((ObjectStreamClass) object, unshared);
            }

            // Is it a String ? (instanceof, but == is faster)
            if (objClass == ObjectStreamClass.STRINGCLASS) {
                return writeNewString((String) object, unshared);
            }

            // Is it an Array ?
            if (objClass.isArray()) {
                return writeNewArray(object, objClass, objClass
                        .getComponentType(), unshared);
            }

            if (object instanceof Enum) {
                return writeNewEnum(object, objClass, unshared);
            }

            // Not a String or Class or Array. Default procedure.
            return writeNewObject(object, objClass, unshared);
        } finally {
            nestedLevels--;
        }
    
protected voidwriteObjectOverride(java.lang.Object object)
Method to be overridden by subclasses to write {@code object} to the target stream.

param
object the object to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        // BEGIN android-changed
        // copied from newer version of harmony
        if (!subclassOverridingImplementation) {
            // Subclasses must override.
            throw new IOException();
        }
        // END android-changed
    
public voidwriteShort(int value)
Writes a short (16 bit) to the target stream.

param
value the short to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeShort(value);
    
protected voidwriteStreamHeader()
Writes the {@link ObjectOutputStream} header to the target stream.

throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        output.writeShort(STREAM_MAGIC);
        output.writeShort(STREAM_VERSION);
    
public voidwriteUTF(java.lang.String value)
Writes a string encoded with {@link DataInput modified UTF-8} to the target stream.

param
value the string to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
since
Android 1.0

        checkWritePrimitiveTypes();
        primitiveTypes.writeUTF(value);
    
public voidwriteUnshared(java.lang.Object object)
Writes an unshared object to the target stream. This method is identical to {@code writeObject}, except that it always writes a new object to the stream versus the use of back-referencing for identical objects by {@code writeObject}.

param
object the object to write to the target stream.
throws
IOException if an error occurs while writing to the target stream.
see
ObjectInputStream#readUnshared()
since
Android 1.0

        writeObject(object, true);