2454 lines · 90.0 KB · Java
RawDownload
/* * 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.