/* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; import java.io.ObjectStreamClass.WeakClassKey;import java.lang.ref.ReferenceQueue;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import static java.io.ObjectStreamClass.processQueue;import java.io.SerialCallbackContext; /** * An ObjectOutputStream writes primitive data types and graphs of Java objects * to an OutputStream. The objects can be read (reconstituted) using an * ObjectInputStream. Persistent storage of objects can be accomplished by * using a file for the stream. If the stream is a network socket stream, the * objects can be reconstituted on another host or in another process. * * <p>Only objects that support the java.io.Serializable interface can be * written to streams. The class of each serializable object is encoded * including the class name and signature of the class, the values of the * object's fields and arrays, and the closure of any other objects referenced * from the initial objects. * * <p>The method writeObject is used to write an object to the stream. Any * object, including Strings and arrays, is written with writeObject. Multiple * objects or primitives can be written to the stream. The objects must be * read back from the corresponding ObjectInputstream with the same types and * in the same order as they were written. * * <p>Primitive data types can also be written to the stream using the * appropriate methods from DataOutput. Strings can also be written using the * writeUTF method. * * <p>The default serialization mechanism for an object writes the class of the * object, the class signature, and the values of all non-transient and * non-static fields. References to other objects (except in transient or * static fields) cause those objects to be written also. Multiple references * to a single object are encoded using a reference sharing mechanism so that * graphs of objects can be restored to the same shape as when the original was * written. * * <p>For example to write an object that can be read by the example in * ObjectInputStream: * <br> * <pre> * FileOutputStream fos = new FileOutputStream("t.tmp"); * ObjectOutputStream oos = new ObjectOutputStream(fos); * * oos.writeInt(12345); * oos.writeObject("Today"); * oos.writeObject(new Date()); * * oos.close(); * </pre> * * <p>Classes that require special handling during the serialization and * deserialization process must implement special methods with these exact * signatures: * <br> * <pre> * private void readObject(java.io.ObjectInputStream stream) * throws IOException, ClassNotFoundException; * private void writeObject(java.io.ObjectOutputStream stream) * throws IOException * private void readObjectNoData() * throws ObjectStreamException; * </pre> * * <p>The writeObject method is responsible for writing the state of the object * for its particular class so that the corresponding readObject method can * restore it. The method does not need to concern itself with the state * belonging to the object's superclasses or subclasses. State is saved by * writing the individual fields to the ObjectOutputStream using the * writeObject method or by using the methods for primitive data types * supported by DataOutput. * * <p>Serialization does not write out the fields of any object that does not * implement the java.io.Serializable interface. Subclasses of Objects that * are not serializable can be serializable. In this case the non-serializable * class must have a no-arg constructor to allow its fields to be initialized. * In this case it is the responsibility of the subclass to save and restore * the state of the non-serializable class. It is frequently the case that the * fields of that class are accessible (public, package, or protected) or that * there are get and set methods that can be used to restore the state. * * <p>Serialization of an object can be prevented by implementing writeObject * and readObject methods that throw the NotSerializableException. The * exception will be caught by the ObjectOutputStream and abort the * serialization process. * * <p>Implementing the Externalizable interface allows the object to assume * complete control over the contents and format of the object's serialized * form. The methods of the Externalizable interface, writeExternal and * readExternal, are called to save and restore the objects state. When * implemented by a class they can write and read their own state using all of * the methods of ObjectOutput and ObjectInput. It is the responsibility of * the objects to handle any versioning that occurs. * * <p>Enum constants are serialized differently than ordinary serializable or * externalizable objects. The serialized form of an enum constant consists * solely of its name; field values of the constant are not transmitted. To * serialize an enum constant, ObjectOutputStream writes the string returned by * the constant's name method. Like other serializable or externalizable * objects, enum constants can function as the targets of back references * appearing subsequently in the serialization stream. The process by which * enum constants are serialized cannot be customized; any class-specific * writeObject and writeReplace methods defined by enum types are ignored * during serialization. Similarly, any serialPersistentFields or * serialVersionUID field declarations are also ignored--all enum types have a * fixed serialVersionUID of 0L. * * <p>Primitive data, excluding serializable fields and externalizable data, is * written to the ObjectOutputStream in block-data records. A block data record * is composed of a header and data. The block data header consists of a marker * and the number of bytes to follow the header. Consecutive primitive data * writes are merged into one block-data record. The blocking factor used for * a block-data record will be 1024 bytes. Each block-data record will be * filled up to 1024 bytes, or be written whenever there is a termination of * block-data mode. Calls to the ObjectOutputStream methods writeObject, * defaultWriteObject and writeFields initially terminate any existing * block-data record. * * @author Mike Warres * @author Roger Riggs * @see java.io.DataOutput * @see java.io.ObjectInputStream * @see java.io.Serializable * @see java.io.Externalizable * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a> * @since JDK1.1 */public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants{ private static class Caches { /** cache of subclass security audit results */ static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = new ConcurrentHashMap<>(); /** queue for WeakReferences to audited subclasses */ static final ReferenceQueue<Class<?>> subclassAuditsQueue = new ReferenceQueue<>(); } /** filter stream for handling block data conversion */ private final BlockDataOutputStream bout; /** obj -> wire handle map */ private final HandleTable handles; /** obj -> replacement obj map */ private final ReplaceTable subs; /** stream protocol version */ private int protocol = PROTOCOL_VERSION_2; /** recursion depth */ private int depth; /** buffer for writing primitive field values */ private byte[] primVals; /** if true, invoke writeObjectOverride() instead of writeObject() */ private final boolean enableOverride; /** if true, invoke replaceObject() */ private boolean enableReplace; // values below valid only during upcalls to writeObject()/writeExternal() /** * Context during upcalls to class-defined writeObject methods; holds * object currently being serialized and descriptor for current class. * Null when not during writeObject upcall. */ private SerialCallbackContext curContext; /** current PutField object */ private PutFieldImpl curPut; /** custom storage for debug trace info */ private final DebugTraceInfoStack debugInfoStack; /** * value of "sun.io.serialization.extendedDebugInfo" property, * as true or false for extended information about exception's place */ private static final boolean extendedDebugInfo = java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "sun.io.serialization.extendedDebugInfo")).booleanValue(); /** * Creates an ObjectOutputStream that writes to the specified OutputStream. * This constructor writes the serialization stream header to the * underlying stream; callers may wish to flush the stream immediately to * ensure that constructors for receiving ObjectInputStreams will not block * when reading the header. * * <p>If a security manager is installed, this constructor will check for * the "enableSubclassImplementation" SerializablePermission when invoked * directly or indirectly by the constructor of a subclass which overrides * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared * methods. * * @param out output stream to write to * @throws IOException if an I/O error occurs while writing stream header * @throws SecurityException if untrusted subclass illegally overrides * security-sensitive methods * @throws NullPointerException if <code>out</code> is <code>null</code> * @since 1.4 * @see ObjectOutputStream#ObjectOutputStream() * @see ObjectOutputStream#putFields() * @see ObjectInputStream#ObjectInputStream(InputStream) */ public ObjectOutputStream(OutputStream out) throws IOException { verifySubclass(); bout = new BlockDataOutputStream(out); handles = new HandleTable(10, (float) 3.00); subs = new ReplaceTable(10, (float) 3.00); enableOverride = false; writeStreamHeader(); bout.setBlockDataMode(true); if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack(); } else { debugInfoStack = null; } } /** * Provide a way for subclasses that are completely reimplementing * ObjectOutputStream to not have to allocate private data just used by * this implementation of ObjectOutputStream. * * <p>If there is a security manager installed, this method first calls the * security manager's <code>checkPermission</code> method with a * <code>SerializablePermission("enableSubclassImplementation")</code> * permission to ensure it's ok to enable subclassing. * * @throws SecurityException if a security manager exists and its * <code>checkPermission</code> method denies enabling * subclassing. * @see SecurityManager#checkPermission * @see java.io.SerializablePermission */ protected ObjectOutputStream() throws IOException, SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } bout = null; handles = null; subs = null; enableOverride = true; debugInfoStack = null; } /** * Specify stream protocol version to use when writing the stream. * * <p>This routine provides a hook to enable the current version of * Serialization to write in a format that is backwards compatible to a * previous version of the stream format. * * <p>Every effort will be made to avoid introducing additional * backwards incompatibilities; however, sometimes there is no * other alternative. * * @param version use ProtocolVersion from java.io.ObjectStreamConstants. * @throws IllegalStateException if called after any objects * have been serialized. * @throws IllegalArgumentException if invalid version is passed in. * @throws IOException if I/O errors occur * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2 * @since 1.2 */ public void useProtocolVersion(int version) throws IOException { if (handles.size() != 0) { // REMIND: implement better check for pristine stream? throw new IllegalStateException("stream non-empty"); } switch (version) { case PROTOCOL_VERSION_1: case PROTOCOL_VERSION_2: protocol = version; break; default: throw new IllegalArgumentException( "unknown version: " + version); } } /** * Write the specified object to the ObjectOutputStream. The class of the * object, the signature of the class, and the values of the non-transient * and non-static fields of the class and all of its supertypes are * written. Default serialization for a class can be overridden using the * writeObject and the readObject methods. Objects referenced by this * object are written transitively so that a complete equivalent graph of * objects can be reconstructed by an ObjectInputStream. * * <p>Exceptions are thrown for problems with the OutputStream and for * classes that should not be serialized. All exceptions are fatal to the * OutputStream, which is left in an indeterminate state, and it is up to * the caller to ignore or recover the stream state. * * @throws InvalidClassException Something is wrong with a class used by * serialization. * @throws NotSerializableException Some object to be serialized does not * implement the java.io.Serializable interface. * @throws IOException Any exception thrown by the underlying * OutputStream. */ public final void writeObject(Object obj) throws IOException { if (enableOverride) { writeObjectOverride(obj); return; } try { writeObject0(obj, false); } catch (IOException ex) { if (depth == 0) { writeFatalException(ex); } throw ex; } } /** * Method used by subclasses to override the default writeObject method. * This method is called by trusted subclasses of ObjectInputStream that * constructed ObjectInputStream using the protected no-arg constructor. * The subclass is expected to provide an override method with the modifier * "final". * * @param obj object to be written to the underlying stream * @throws IOException if there are I/O errors while writing to the * underlying stream * @see #ObjectOutputStream() * @see #writeObject(Object) * @since 1.2 */ protected void writeObjectOverride(Object obj) throws IOException { } /** * Writes an "unshared" object to the ObjectOutputStream. This method is * identical to writeObject, except that it always writes the given object * as a new, unique object in the stream (as opposed to a back-reference * pointing to a previously serialized instance). Specifically: * <ul> * <li>An object written via writeUnshared is always serialized in the * same manner as a newly appearing object (an object that has not * been written to the stream yet), regardless of whether or not the * object has been written previously. * * <li>If writeObject is used to write an object that has been previously * written with writeUnshared, the previous writeUnshared operation * is treated as if it were a write of a separate object. In other * words, ObjectOutputStream will never generate back-references to * object data written by calls to writeUnshared. * </ul> * While writing an object via writeUnshared does not in itself guarantee a * unique reference to the object when it is deserialized, it allows a * single object to be defined multiple times in a stream, so that multiple * calls to readUnshared by the receiver will not conflict. Note that the * rules described above only apply to the base-level object written with * writeUnshared, and not to any transitively referenced sub-objects in the * object graph to be serialized. * * <p>ObjectOutputStream subclasses which override this method can only be * constructed in security contexts possessing the * "enableSubclassImplementation" SerializablePermission; any attempt to * instantiate such a subclass without this permission will cause a * SecurityException to be thrown. * * @param obj object to write to stream * @throws NotSerializableException if an object in the graph to be * serialized does not implement the Serializable interface * @throws InvalidClassException if a problem exists with the class of an * object to be serialized * @throws IOException if an I/O error occurs during serialization * @since 1.4 */ public void writeUnshared(Object obj) throws IOException { try { writeObject0(obj, true); } catch (IOException ex) { if (depth == 0) { writeFatalException(ex); } throw ex; } } /** * Write the non-static and non-transient fields of the current class to * this stream. This may only be called from the writeObject method of the * class being serialized. It will throw the NotActiveException if it is * called otherwise. * * @throws IOException if I/O errors occur while writing to the underlying * <code>OutputStream</code> */ public void defaultWriteObject() throws IOException { if ( curContext == null ) { throw new NotActiveException("not in call to writeObject"); } Object curObj = curContext.getObj(); ObjectStreamClass curDesc = curContext.getDesc(); bout.setBlockDataMode(false); defaultWriteFields(curObj, curDesc); bout.setBlockDataMode(true); } /** * Retrieve the object used to buffer persistent fields to be written to * the stream. The fields will be written to the stream when writeFields * method is called. * * @return an instance of the class Putfield that holds the serializable * fields * @throws IOException if I/O errors occur * @since 1.2 */ public ObjectOutputStream.PutField putFields() throws IOException { if (curPut == null) { if (curContext == null) { throw new NotActiveException("not in call to writeObject"); } Object curObj = curContext.getObj(); ObjectStreamClass curDesc = curContext.getDesc(); curPut = new PutFieldImpl(curDesc); } return curPut; } /** * Write the buffered fields to the stream. * * @throws IOException if I/O errors occur while writing to the underlying * stream * @throws NotActiveException Called when a classes writeObject method was * not called to write the state of the object. * @since 1.2 */ public void writeFields() throws IOException { if (curPut == null) { throw new NotActiveException("no current PutField object"); } bout.setBlockDataMode(false); curPut.writeFields(); bout.setBlockDataMode(true); } /** * Reset will disregard the state of any objects already written to the * stream. The state is reset to be the same as a new ObjectOutputStream. * The current point in the stream is marked as reset so the corresponding * ObjectInputStream will be reset at the same point. Objects previously * written to the stream will not be refered to as already being in the * stream. They will be written to the stream again. * * @throws IOException if reset() is invoked while serializing an object. */ public void reset() throws IOException { if (depth != 0) { throw new IOException("stream active"); } bout.setBlockDataMode(false); bout.writeByte(TC_RESET); clear(); bout.setBlockDataMode(true); }Lines 1–500 of 2454. Load more
/* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; import java.io.ObjectStreamClass.WeakClassKey; import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; import java.io.SerialCallbackContext; /** * An ObjectOutputStream writes primitive data types and graphs of Java objects * to an OutputStream. The objects can be read (reconstituted) using an * ObjectInputStream. Persistent storage of objects can be accomplished by * using a file for the stream. If the stream is a network socket stream, the * objects can be reconstituted on another host or in another process. * * <p>Only objects that support the java.io.Serializable interface can be * written to streams. The class of each serializable object is encoded * including the class name and signature of the class, the values of the * object's fields and arrays, and the closure of any other objects referenced * from the initial objects. * * <p>The method writeObject is used to write an object to the stream. Any * object, including Strings and arrays, is written with writeObject. Multiple * objects or primitives can be written to the stream. The objects must be * read back from the corresponding ObjectInputstream with the same types and * in the same order as they were written. * * <p>Primitive data types can also be written to the stream using the * appropriate methods from DataOutput. Strings can also be written using the * writeUTF method. * * <p>The default serialization mechanism for an object writes the class of the * object, the class signature, and the values of all non-transient and * non-static fields. References to other objects (except in transient or * static fields) cause those objects to be written also. Multiple references * to a single object are encoded using a reference sharing mechanism so that * graphs of objects can be restored to the same shape as when the original was * written. * * <p>For example to write an object that can be read by the example in * ObjectInputStream: * <br> * <pre> * FileOutputStream fos = new FileOutputStream("t.tmp"); * ObjectOutputStream oos = new ObjectOutputStream(fos); * * oos.writeInt(12345); * oos.writeObject("Today"); * oos.writeObject(new Date()); * * oos.close(); * </pre> * * <p>Classes that require special handling during the serialization and * deserialization process must implement special methods with these exact * signatures: * <br> * <pre> * private void readObject(java.io.ObjectInputStream stream) * throws IOException, ClassNotFoundException; * private void writeObject(java.io.ObjectOutputStream stream) * throws IOException * private void readObjectNoData() * throws ObjectStreamException; * </pre> * * <p>The writeObject method is responsible for writing the state of the object * for its particular class so that the corresponding readObject method can * restore it. The method does not need to concern itself with the state * belonging to the object's superclasses or subclasses. State is saved by * writing the individual fields to the ObjectOutputStream using the * writeObject method or by using the methods for primitive data types * supported by DataOutput. * * <p>Serialization does not write out the fields of any object that does not * implement the java.io.Serializable interface. Subclasses of Objects that * are not serializable can be serializable. In this case the non-serializable * class must have a no-arg constructor to allow its fields to be initialized. * In this case it is the responsibility of the subclass to save and restore * the state of the non-serializable class. It is frequently the case that the * fields of that class are accessible (public, package, or protected) or that * there are get and set methods that can be used to restore the state. * * <p>Serialization of an object can be prevented by implementing writeObject * and readObject methods that throw the NotSerializableException. The * exception will be caught by the ObjectOutputStream and abort the * serialization process. * * <p>Implementing the Externalizable interface allows the object to assume * complete control over the contents and format of the object's serialized * form. The methods of the Externalizable interface, writeExternal and * readExternal, are called to save and restore the objects state. When * implemented by a class they can write and read their own state using all of * the methods of ObjectOutput and ObjectInput. It is the responsibility of * the objects to handle any versioning that occurs. * * <p>Enum constants are serialized differently than ordinary serializable or * externalizable objects. The serialized form of an enum constant consists * solely of its name; field values of the constant are not transmitted. To * serialize an enum constant, ObjectOutputStream writes the string returned by * the constant's name method. Like other serializable or externalizable * objects, enum constants can function as the targets of back references * appearing subsequently in the serialization stream. The process by which * enum constants are serialized cannot be customized; any class-specific * writeObject and writeReplace methods defined by enum types are ignored * during serialization. Similarly, any serialPersistentFields or * serialVersionUID field declarations are also ignored--all enum types have a * fixed serialVersionUID of 0L. * * <p>Primitive data, excluding serializable fields and externalizable data, is * written to the ObjectOutputStream in block-data records. A block data record * is composed of a header and data. The block data header consists of a marker * and the number of bytes to follow the header. Consecutive primitive data * writes are merged into one block-data record. The blocking factor used for * a block-data record will be 1024 bytes. Each block-data record will be * filled up to 1024 bytes, or be written whenever there is a termination of * block-data mode. Calls to the ObjectOutputStream methods writeObject, * defaultWriteObject and writeFields initially terminate any existing * block-data record. * * @author Mike Warres * @author Roger Riggs * @see java.io.DataOutput * @see java.io.ObjectInputStream * @see java.io.Serializable * @see java.io.Externalizable * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a> * @since JDK1.1 */ public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { private static class Caches { /** cache of subclass security audit results */ static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = new ConcurrentHashMap<>(); /** queue for WeakReferences to audited subclasses */ static final ReferenceQueue<Class<?>> subclassAuditsQueue = new ReferenceQueue<>(); } /** filter stream for handling block data conversion */ private final BlockDataOutputStream bout; /** obj -> wire handle map */ private final HandleTable handles; /** obj -> replacement obj map */ private final ReplaceTable subs; /** stream protocol version */ private int protocol = PROTOCOL_VERSION_2; /** recursion depth */ private int depth; /** buffer for writing primitive field values */ private byte[] primVals; /** if true, invoke writeObjectOverride() instead of writeObject() */ private final boolean enableOverride; /** if true, invoke replaceObject() */ private boolean enableReplace; // values below valid only during upcalls to writeObject()/writeExternal() /** * Context during upcalls to class-defined writeObject methods; holds * object currently being serialized and descriptor for current class. * Null when not during writeObject upcall. */ private SerialCallbackContext curContext; /** current PutField object */ private PutFieldImpl curPut; /** custom storage for debug trace info */ private final DebugTraceInfoStack debugInfoStack; /** * value of "sun.io.serialization.extendedDebugInfo" property, * as true or false for extended information about exception's place */ private static final boolean extendedDebugInfo = java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "sun.io.serialization.extendedDebugInfo")).booleanValue(); /** * Creates an ObjectOutputStream that writes to the specified OutputStream. * This constructor writes the serialization stream header to the * underlying stream; callers may wish to flush the stream immediately to * ensure that constructors for receiving ObjectInputStreams will not block * when reading the header. * * <p>If a security manager is installed, this constructor will check for * the "enableSubclassImplementation" SerializablePermission when invoked * directly or indirectly by the constructor of a subclass which overrides * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared * methods. * * @param out output stream to write to * @throws IOException if an I/O error occurs while writing stream header * @throws SecurityException if untrusted subclass illegally overrides * security-sensitive methods * @throws NullPointerException if <code>out</code> is <code>null</code> * @since 1.4 * @see ObjectOutputStream#ObjectOutputStream() * @see ObjectOutputStream#putFields() * @see ObjectInputStream#ObjectInputStream(InputStream) */ public ObjectOutputStream(OutputStream out) throws IOException { verifySubclass(); bout = new BlockDataOutputStream(out); handles = new HandleTable(10, (float) 3.00); subs = new ReplaceTable(10, (float) 3.00); enableOverride = false; writeStreamHeader(); bout.setBlockDataMode(true); if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack(); } else { debugInfoStack = null; } } /** * Provide a way for subclasses that are completely reimplementing * ObjectOutputStream to not have to allocate private data just used by * this implementation of ObjectOutputStream. * * <p>If there is a security manager installed, this method first calls the * security manager's <code>checkPermission</code> method with a * <code>SerializablePermission("enableSubclassImplementation")</code> * permission to ensure it's ok to enable subclassing. * * @throws SecurityException if a security manager exists and its * <code>checkPermission</code> method denies enabling * subclassing. * @see SecurityManager#checkPermission * @see java.io.SerializablePermission */ protected ObjectOutputStream() throws IOException, SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } bout = null; handles = null; subs = null; enableOverride = true; debugInfoStack = null; } /** * Specify stream protocol version to use when writing the stream. * * <p>This routine provides a hook to enable the current version of * Serialization to write in a format that is backwards compatible to a * previous version of the stream format. * * <p>Every effort will be made to avoid introducing additional * backwards incompatibilities; however, sometimes there is no * other alternative. * * @param version use ProtocolVersion from java.io.ObjectStreamConstants. * @throws IllegalStateException if called after any objects * have been serialized. * @throws IllegalArgumentException if invalid version is passed in. * @throws IOException if I/O errors occur * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2 * @since 1.2 */ public void useProtocolVersion(int version) throws IOException { if (handles.size() != 0) { // REMIND: implement better check for pristine stream? throw new IllegalStateException("stream non-empty"); } switch (version) { case PROTOCOL_VERSION_1: case PROTOCOL_VERSION_2: protocol = version; break; default: throw new IllegalArgumentException( "unknown version: " + version); } } /** * Write the specified object to the ObjectOutputStream. The class of the * object, the signature of the class, and the values of the non-transient * and non-static fields of the class and all of its supertypes are * written. Default serialization for a class can be overridden using the * writeObject and the readObject methods. Objects referenced by this * object are written transitively so that a complete equivalent graph of * objects can be reconstructed by an ObjectInputStream. * * <p>Exceptions are thrown for problems with the OutputStream and for * classes that should not be serialized. All exceptions are fatal to the * OutputStream, which is left in an indeterminate state, and it is up to * the caller to ignore or recover the stream state. * * @throws InvalidClassException Something is wrong with a class used by * serialization. * @throws NotSerializableException Some object to be serialized does not * implement the java.io.Serializable interface. * @throws IOException Any exception thrown by the underlying * OutputStream. */ public final void writeObject(Object obj) throws IOException { if (enableOverride) { writeObjectOverride(obj); return; } try { writeObject0(obj, false); } catch (IOException ex) { if (depth == 0) { writeFatalException(ex); } throw ex; } } /** * Method used by subclasses to override the default writeObject method. * This method is called by trusted subclasses of ObjectInputStream that * constructed ObjectInputStream using the protected no-arg constructor. * The subclass is expected to provide an override method with the modifier * "final". * * @param obj object to be written to the underlying stream * @throws IOException if there are I/O errors while writing to the * underlying stream * @see #ObjectOutputStream() * @see #writeObject(Object) * @since 1.2 */ protected void writeObjectOverride(Object obj) throws IOException { } /** * Writes an "unshared" object to the ObjectOutputStream. This method is * identical to writeObject, except that it always writes the given object * as a new, unique object in the stream (as opposed to a back-reference * pointing to a previously serialized instance). Specifically: * <ul> * <li>An object written via writeUnshared is always serialized in the * same manner as a newly appearing object (an object that has not * been written to the stream yet), regardless of whether or not the * object has been written previously. * * <li>If writeObject is used to write an object that has been previously * written with writeUnshared, the previous writeUnshared operation * is treated as if it were a write of a separate object. In other * words, ObjectOutputStream will never generate back-references to * object data written by calls to writeUnshared. * </ul> * While writing an object via writeUnshared does not in itself guarantee a * unique reference to the object when it is deserialized, it allows a * single object to be defined multiple times in a stream, so that multiple * calls to readUnshared by the receiver will not conflict. Note that the * rules described above only apply to the base-level object written with * writeUnshared, and not to any transitively referenced sub-objects in the * object graph to be serialized. * * <p>ObjectOutputStream subclasses which override this method can only be * constructed in security contexts possessing the * "enableSubclassImplementation" SerializablePermission; any attempt to * instantiate such a subclass without this permission will cause a * SecurityException to be thrown. * * @param obj object to write to stream * @throws NotSerializableException if an object in the graph to be * serialized does not implement the Serializable interface * @throws InvalidClassException if a problem exists with the class of an * object to be serialized * @throws IOException if an I/O error occurs during serialization * @since 1.4 */ public void writeUnshared(Object obj) throws IOException { try { writeObject0(obj, true); } catch (IOException ex) { if (depth == 0) { writeFatalException(ex); } throw ex; } } /** * Write the non-static and non-transient fields of the current class to * this stream. This may only be called from the writeObject method of the * class being serialized. It will throw the NotActiveException if it is * called otherwise. * * @throws IOException if I/O errors occur while writing to the underlying * <code>OutputStream</code> */ public void defaultWriteObject() throws IOException { if ( curContext == null ) { throw new NotActiveException("not in call to writeObject"); } Object curObj = curContext.getObj(); ObjectStreamClass curDesc = curContext.getDesc(); bout.setBlockDataMode(false); defaultWriteFields(curObj, curDesc); bout.setBlockDataMode(true); } /** * Retrieve the object used to buffer persistent fields to be written to * the stream. The fields will be written to the stream when writeFields * method is called. * * @return an instance of the class Putfield that holds the serializable * fields * @throws IOException if I/O errors occur * @since 1.2 */ public ObjectOutputStream.PutField putFields() throws IOException { if (curPut == null) { if (curContext == null) { throw new NotActiveException("not in call to writeObject"); } Object curObj = curContext.getObj(); ObjectStreamClass curDesc = curContext.getDesc(); curPut = new PutFieldImpl(curDesc); } return curPut; } /** * Write the buffered fields to the stream. * * @throws IOException if I/O errors occur while writing to the underlying * stream * @throws NotActiveException Called when a classes writeObject method was * not called to write the state of the object. * @since 1.2 */ public void writeFields() throws IOException { if (curPut == null) { throw new NotActiveException("no current PutField object"); } bout.setBlockDataMode(false); curPut.writeFields(); bout.setBlockDataMode(true); } /** * Reset will disregard the state of any objects already written to the * stream. The state is reset to be the same as a new ObjectOutputStream. * The current point in the stream is marked as reset so the corresponding * ObjectInputStream will be reset at the same point. Objects previously * written to the stream will not be refered to as already being in the * stream. They will be written to the stream again. * * @throws IOException if reset() is invoked while serializing an object. */ public void reset() throws IOException { if (depth != 0) { throw new IOException("stream active"); } bout.setBlockDataMode(false); bout.writeByte(TC_RESET); clear(); bout.setBlockDataMode(true); }