objectinputstream.java

来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,730 行 · 第 1/4 页

JAVA
1,730
字号
/*
 * @(#)ObjectInputStream.java	1.41 98/07/09
 *
 * Copyright 1995-1998 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 * 
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

package java.io;

import java.util.Vector;
import java.util.Stack;
import java.util.Hashtable;

import sun.io.ObjectInputStreamDelegate; // RMI over IIOP hook.

/**
 * An ObjectInputStream deserializes primitive data and objects previously
 * written using an ObjectOutputStream.
 * 
 * ObjectOutputStream and ObjectInputStream can provide an application
 * with persistent storage for graphs of objects when used with a
 * FileOutputStream and FileInputStream respectively.
 * ObjectInputStream is used to recover those objects previously
 * serialized. Other uses include passing objects between hosts using
 * a socket stream or for marshaling and unmarshaling arguments and
 * parameters in a remote communication system.<p>
 *
 * ObjectInputStream ensures that the types of all objects in the
 * graph created from the stream match the classes present in the
 * Java Virtual Machine.  Classes are loaded as required using the
 * standard mechanisms. <p>
 *
 * Only objects that support the java.io.Serializable or
 * java.io.Externalizable interface can be read from streams.
 *
 * The method <STRONG>readObject</STRONG> is used to read an object
 * from the stream.  Java's safe casting should be used to get the
 * desired type.  In Java, strings and arrays are objects and are
 * treated as objects during serialization. When read they need to be
 * cast to the expected type.<p>
 *
 * Primitive data types can be read from the stream using the appropriate
 * method on DataInput. <p>
 * 
 * The default deserialization mechanism for objects restores the
 * contents of each field to the value and type it had when it was written.
 * Fields declared as transient or static are ignored by the
 * deserialization process.  References to other objects cause those
 * objects to be read from the stream as necessary.  Graphs of objects
 * are restored correctly using a reference sharing mechanism.  New
 * objects are always allocated when deserializing, which prevents
 * existing objects from being overwritten. <p>
 *
 * Reading an object is analogous to running the constructors of a new
 * object.  Memory is allocated for the object and initialized to zero
 * (NULL).  No-arg constructors are invoked for the non-serializable
 * classes and then the fields of the serializable classes are
 * restored from the stream starting with the serializable class closest to
 * java.lang.object and finishing with the object's most specifiec
 * class. <p>
 *
 * For example to read from a stream as written by the example in
 * ObjectOutputStream: <br>
 *
 * <PRE>
 *	FileInputStream istream = new FileInputStream("t.tmp");
 *	ObjectInputStream p = new ObjectInputStream(istream);
 *
 *	int i = p.readInt();
 *	String today = (String)p.readObject();
 *	Date date = (Date)p.readObject();
 *
 *	istream.close();
 * </PRE>
 *
 * Classes control how they are serialized by implementing either the
 * java.io.Serializable or java.io.Externalizable interfaces.<P>
 *
 * Implementing the Serializable interface allows object serialization
 * to save and restore the entire state of the object and it allows
 * classes to evolve between the time the stream is written and the time it is
 * read.  It automatically traverses references between objects,
 * saving and restoring entire graphs.
 *
 * Serializable classes that require special handling during the
 * serialization and deserialization process should implement both
 * of these methods:<p>
 *
 * <PRE>
 * private void writeObject(java.io.ObjectOutputStream stream)
 *     throws IOException;
 * private void readObject(java.io.ObjectInputStream stream)
 *     throws IOException, ClassNotFoundException; 
 * </PRE><p>
 *
 * The readObject method is responsible for reading and restoring the
 * state of the object for its particular class using data written to
 * the stream by the corresponding writeObject method.  The method
 * does not need to concern itself with the state belonging to its
 * superclasses or subclasses.  State is restored by reading data from
 * the ObjectInputStream for the individual fields and making
 * assignments to the appropriate fields of the object.  Reading
 * primitive data types is supported by DataInput. <p>
 *
 * Serialization does not read or assign values to 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>
 *
 * Any exception that occurs while deserializing an object will be
 * caught by the ObjectInputStream and abort the reading 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.
 *
 * @author  Roger Riggs
 * @version 1.41, 07/09/98
 * @see java.io.DataInput
 * @see java.io.ObjectOutputStream
 * @see java.io.Serializable
 * @since   JDK1.1
 */
public class ObjectInputStream extends InputStream
	implements ObjectInput, ObjectStreamConstants
{ 
    /**
     * Create an ObjectInputStream that reads from the specified InputStream.
     * The stream header containing the magic number and version number
     * are read from the stream and verified. This method will block
     * until the corresponding ObjectOutputStream has written and flushed the header.
     * @exception StreamCorruptedException The version or magic number are incorrect.
     * @exception IOException An exception occurred in the underlying stream.
     * @since     JDK1.1
     */
    public ObjectInputStream(InputStream in)
	throws IOException, StreamCorruptedException
  {
        /*
         * RMI over IIOP hook. Check if we are a trusted subclass
         * that has implemented the "sun.io.ObjectInputStream"
         * interface. If so, set our private flag that will be
         * checked in "readObject", "defaultReadObject" and
         * "enableResolveObject". Note that we don't initialize
         * private instance variables in this case as an optimization
         * (subclasses using the hook should have no need for them).
         */
        
        if (this instanceof sun.io.ObjectInputStreamDelegate && this.getClass().getClassLoader() == null) {
            isTrustedSubclass = true;
            return;
        }
        
  	/*
  	 * Save the input stream to read bytes from
  	 * Create a DataInputStream used to read primitive types.
  	 * Setup the DataInputStream to read from this ObjectInputStream
  	 */
	this.in = in;
	dis  = new DataInputStream(this); 
	readStreamHeader();
	resetStream();
    }

    /**
     * Read an object from the ObjectInputStream.
     * 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 read.  Default deserializing for a class can be
     * overriden using the writeObject and readObject methods.
     * Objects referenced by this object are read transitively so
     * that a complete equivalent graph of objects is reconstructed by readObject. <p>
     *
     * The root object is completly restored when all of its fields
     * and the objects it references are completely restored.  At this
     * point the object validation callbacks are executed in order
     * based on their registered priorities. The callbacks are
     * registered by objects (in the readObject special methods)
     * as they are individually restored.
     *
     * Exceptions are thrown for problems with the InputStream and for classes
     * that should not be deserialized.  All exceptions are fatal to the 
     * InputStream and leave it in an indeterminate state; it is up to the caller
     * to ignore or recover the stream state.
     * @exception java.lang.ClassNotFoundException Class of a serialized object
     *      cannot be found.
     * @exception InvalidClassException Something is wrong with a class used by
     *     serialization.
     * @exception StreamCorruptedException Control information in the
     *     stream is inconsistent.
     * @exception OptionalDataException Primitive data was found in the 
     * stream instead of objects.
     * @exception IOException Any of the usual Input/Output related exceptions.
     * @since     JDK1.1
     */
    public final Object readObject()
 	throws OptionalDataException, ClassNotFoundException, IOException {
 	
 	    /*
 	     * RMI over IIOP hook. Invoke delegate method if indicated.
 	     */
 	    if (isTrustedSubclass) {
 	        return ((ObjectInputStreamDelegate) this).readObjectDelegate();
 	    }
 	    
 	    /* require local Class for object by default. */
 	    return readObject(true);
    }
 
    /*
      * Private implementation of Read an object from the ObjectInputStream.
      *
      * @param requireLocalClass If false, do not throw ClassNotFoundException
      *                          when local class does not exist.
      *
      * @since     JDK1.2
      */
    private final Object readObject(boolean requireLocalClass)
	throws OptionalDataException, ClassNotFoundException, IOException
    {
	/* If the stream is in blockData mode and there's any data
	 * left throw an exception to report how much there is.
	 */
	if (blockDataMode) {
	    /* Can't use member method available() since it depends on the unreliable
	     *  method InputStream.available().
	     */
	    if (count == 0)
		refill();
	    if (count > 0)
		throw new OptionalDataException(count);
	}
	
	/*
	 * Look ahead now to absorb any pending reset's.
	 * Before changing the state.
	 */
	peekCode();

	/* Save the current state and get ready to read an object. */
	Object prevObject = currentObject;
	ObjectStreamClass prevClass = currentClassDesc;
	boolean prevBlockDataMode = setBlockData(false);
	
	recursionDepth++;	// Entering
	Object obj = null;

	/* 
	 * Check for reset, handle it before reading an object.
	 */

	byte rcode;
	rcode = readCode();
	try {
	    /*
	     * Dispatch on the next code in the stream.
	     */
	    int wireoffset = -1;

	    switch (rcode) {
		
	    case TC_NULL:
		obj = null;
		break;
		
	    case TC_REFERENCE: 
		/* This is a reference to a pre-existing object */
		wireoffset = readInt() - baseWireHandle; 
		
		try {
		    obj = wireHandle2Object.elementAt(wireoffset);
		} catch (ArrayIndexOutOfBoundsException e) {
		    throw new StreamCorruptedException("Reference to object never serialized.");
		}
		break;
		
	    case TC_STRING:
		{
		    obj = readUTF(); 
		    Object localObj = obj; //readUTF does not set currentObject
		    wireoffset = assignWireOffset(obj);

		    /* Allow subclasses to replace the object */
		    if (enableResolve) {
			obj = resolveObject(obj);
		    }

		    if (obj != localObj)
			wireHandle2Object.setElementAt(obj, wireoffset);
		}
		break;
		
	    case TC_CLASS:
		ObjectStreamClass v = 
		    (ObjectStreamClass)readObject(requireLocalClass);
		if (v == null) {
		    /*
		     * No class descriptor in stream or class not serializable
		     */
		    throw new StreamCorruptedException("Class not in stream");
		}
		obj = v.forClass();
		if (obj == null && requireLocalClass) {
		    throw new ClassNotFoundException(v.getName());
		}
		assignWireOffset(obj);
		break;
		
	    case TC_CLASSDESC:
		obj = inputClassDescriptor();
		break;
		
	    case TC_ARRAY:
		wireoffset = inputArray(requireLocalClass);
		obj = currentObject;
		/* Allow subclasses to replace the object */
		if (enableResolve) {
		    obj = resolveObject(obj);
		}

		if (obj != currentObject)
		    wireHandle2Object.setElementAt(obj, wireoffset);
		break;
		
	    case TC_OBJECT:
		wireoffset = inputObject(requireLocalClass);
		obj = currentObject;
		if (enableResolve) {
		    /* Hook for alternate object */
		    obj = resolveObject(obj);
		    wireHandle2Object.setElementAt(obj, wireoffset);
		}
		break;
		
	    case TC_ENDBLOCKDATA:
		if (!prevBlockDataMode)
		    throw new StreamCorruptedException("Unexpected end of block data");
		pushbackCode(TC_ENDBLOCKDATA);
		count = -1;	/* Flag EOF */ 
		throw new OptionalDataException(true);
		
	    case TC_BLOCKDATA:
	    case TC_BLOCKDATALONG:
		if (rcode == TC_BLOCKDATALONG) { /* long block: 32 bit size */
		    int b3 = in.read();
		    int b2 = in.read();
		    int b1 = in.read();
		    int b0 = in.read();
		    if ((b3 | b2 | b1 | b0) < 0)
			throw new StreamCorruptedException("EOF expecting count");
		    count = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
		    if (count < 0)
			throw new StreamCorruptedException("Negative block data size");
		} else {			/* normal block: 8 bit size */
		    count = in.read();
		    if (count < 0)
			throw new StreamCorruptedException("EOF expecting count");
		}

    		if (!prevBlockDataMode)
		    throw new StreamCorruptedException("Unexpected blockdata");
		
		throw new OptionalDataException(count);
		
	    case TC_EXCEPTION:
		/* An exception happened during writing, reset the
		 * stream, read the exception, reset the stream and
		 * throw a writeAbortedException with the exception
		 * that was read.
		 */
		resetStream();
		IOException ee = (IOException)readObject();
		resetStream();
		throw new WriteAbortedException("Writing aborted by exception", ee);

	    default:
		throw new StreamCorruptedException("Unknown code in readObject " + rcode);
	    }
	} catch (OptionalDataException optdata) {
	    /* OptionalDataExceptions won't terminate everything.
	     * so just rethrow it.
	     */
	    throw optdata;
	} catch(IOException ee) {
	    if (abortIOException == null && abortClassNotFoundException == null)
		abortIOException = ee;
	} catch(ClassNotFoundException ee) {
	    if (abortIOException == null && abortClassNotFoundException == null)
		abortClassNotFoundException = ee;
	} finally {
	    recursionDepth --;
	    currentObject = prevObject;
	    currentClassDesc = prevClass;
	    currentClass = currentClassDesc != null ? 
		currentClassDesc.forClass() : null;
	    setBlockData(prevBlockDataMode);
	}
	
	/* Check for thrown exceptions and re-throw them, clearing them if
	 * this is the last recursive call .
	 */
	IOException exIOE = abortIOException;
	if (recursionDepth == 0)
	    abortIOException = null;
	if (exIOE != null)
	    throw exIOE;

	
	ClassNotFoundException exCNF = abortClassNotFoundException;
	if (recursionDepth == 0)
	    abortClassNotFoundException = null;
	if (exCNF != null) {
	    throw exCNF;
	}
	

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?