objectinputstream.java

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

JAVA
1,730
字号
	// Check if this is the last nested read, if so
	// Call the validations
	if (recursionDepth == 0) {
	    doValidations();
	}

	return obj;
    }

    /**
     * Read the non-static and non-transient fields of the current class
     * from this stream.  This may only be called from the readObject method
     * of the class being deserialized. It will throw the NotActiveException
     * if it is called otherwise.
     *
     * @exception java.lang.ClassNotFoundException if the class of a serialized
     *              object could not be found.
     * @exception IOException        if an I/O error occurs.
     * @exception NotActiveException if the stream is not currently reading
     *              objects.
     * @since     JDK1.1
     */
    public final void defaultReadObject()
	throws IOException, ClassNotFoundException, NotActiveException
    {
 	
	/*
	 * RMI over IIOP hook. Invoke delegate method if indicated.
	 */
	if (isTrustedSubclass) {
	    ((ObjectInputStreamDelegate) this).defaultReadObjectDelegate();
	    return;
	}
 	    
	if (currentObject == null || currentClassDesc == null)
	    throw new NotActiveException("defaultReadObject");
	

	if (currentClassDesc.getFieldSequence() != null) {
	    boolean prevmode = setBlockData(false);
	    inputClassFields(currentObject, currentClass,
			     currentClassDesc.getFieldSequence());
	    setBlockData(prevmode);
	}
    }
    
    /**
     * Register an object to be validated before the graph is
     * returned.  While similar to resolveObject these validations are
     * called after the entire graph has been reconstituted.
     * Typically, a readObject method will register the object with
     * the stream so that when all of the objects are restored a final
     * set of validations can be performed.
     * @param obj the object to receive the validation callback.
     * @param prio controls the order of callbacks;zero is a good default.
     * Use higher numbers to be called back earlier, lower numbers for later
     * callbacks. Within a priority, callbacks are processed in no
     * particular order.
     *
     * @exception NotActiveException The stream is not currently reading objects
     * so it is invalid to register a callback.
     * @exception InvalidObjectException The validation object is null.
     * @since     JDK1.1
     */
    public synchronized void registerValidation(ObjectInputValidation obj,
						int prio)
	throws NotActiveException, InvalidObjectException
    {
	if (recursionDepth == 0) {
	    throw new NotActiveException("readObject not Active");
	}
	if (obj == null) {
	    throw new InvalidObjectException("Null is not a valid callback object");
	}

	ValidationCallback cb = new ValidationCallback(obj, prio);

	if (callbacks == null) {
	    callbacks = new Vector(100,100);
	}
	// insert at the end if the priority is less than or equal to
	// the last element.
	if (callbacks.isEmpty() ||
	    ((ValidationCallback)(callbacks.lastElement())).priority >= prio) {
	    callbacks.addElement(cb);
	    return;
	}

	// search for the element with priority that is <= to the new
	// priority, insert before it. 
	int size = callbacks.size();
	for (int i = 0; i < size; i++) {
	    ValidationCallback curr = (ValidationCallback)callbacks.elementAt(i);
	    if (curr.priority <= prio) {
		callbacks.insertElementAt(cb, i);
		break;
	    }
	}
    }

    /*
     * If any validations are pending, do them and cleanup the validation vector
     * if an exception is raised, it is passed on to abort the deserialization.
     */
    private void doValidations() throws InvalidObjectException {
	if (callbacks == null)
	    return;
	
	int size = callbacks.size();
	if (size == 0)
	    return;
	
	for (int i = 0; i < size; i++) {
	    ValidationCallback curr = (ValidationCallback)callbacks.elementAt(i);
	    curr.callback.validateObject();
	}
	/* All pending validations completed successfully. Reset.*/
	callbacks.setSize(0);
    }

    /**
     * Subclasses may implement this method to allow classes to be
     * fetched from an alternate source. 
     *
     * The corresponding method in ObjectOutputStream is
     * annotateClass.  This method will be invoked only once for each
     * unique class in the stream.  This method can be implemented by
     * subclasses to use an alternate loading mechanism but must
     * return a Class object.  Once returned, the serialVersionUID of the
     * class is compared to the serialVersionUID of the serialized class.
     * If there is a mismatch, the deserialization fails and an exception
     * is raised. <p>
     *
     * By default the class name is resolved relative to the class
     * that called readObject. <p>
     *
     * @exception ClassNotFoundException If class of
     * a serialized object cannot be found.
     * @since     JDK1.1
     */
    protected Class resolveClass(ObjectStreamClass v)
	throws IOException, ClassNotFoundException
    {
	/* Resolve by looking up the stack for a non-zero class
	 * loader. If not found use the system loader.
	 */
	return loadClass0(null, v.getName());
    }

    /* Resolve a class name relative to the specified class.  If the
     * class is null find the first available class loader up the
     * stack.  This will resolve classes relative to the caller of
     * ObjectInputStream instead of the itself. Classes must be
     * loaded/resolved relative to the application.
     */
    private native Class loadClass0(Class cl, String classname)
	throws ClassNotFoundException;

    /**
     * This method will allow trusted subclasses of ObjectInputStream
     * to substitute one object for another during
     * deserialization. Replacing objects is disabled until
     * enableResolveObject is called. The enableResolveObject method
     * checks that the stream requesting to resolve object can be
     * trusted. Every reference to serializable objects is passed to
     * resolveObject.  To insure that the private state of objects is
     * not unintentionally exposed only trusted streams may use
     * resolveObject. <p>
     *
     * This method is called after an object has been read but before it is
     * returned from readObject.  The default resolveObject method
     * just returns the new object. <p>
     *
     * When a subclass is replacing objects it must insure that the
     * substituted object is compatible with every field where the
     * reference will be stored.  Objects whose type is not a subclass
     * of the type of the field or array element abort the
     * serialization by raising an exception and the object is not be
     * stored. <p>
     *
     * This method is called only once when each object is first encountered.
     * All subsequent references to the object will be redirected to the
     * new object. <P>
     *
     * @exception IOException Any of the usual Input/Output exceptions.
     * @since     JDK1.1
     */
    protected Object resolveObject(Object obj)
    	throws IOException
    {
	return obj;
    }

    /**
     * Enable the stream to allow objects read from the stream to be replaced.
     * If the stream is a trusted class it is allowed to enable replacment.
     * Trusted classes are those classes with a classLoader equals null. <p>
     * 
     * When enabled the resolveObject method is called for every object
     * being deserialized.
     * 
     * @exception SecurityException The classloader of this stream object is non-null.
     * @since     JDK1.1
     */
    protected final boolean enableResolveObject(boolean enable)
	throws SecurityException
    {
 	
	/*
	 * RMI over IIOP hook. Invoke delegate method if indicated.
	 */
	if (isTrustedSubclass) {
	  return ((ObjectInputStreamDelegate) this).enableResolveObjectDelegate(enable);
	}
 	    
	boolean previous = enableResolve;
	if (enable) {
	    ClassLoader loader = this.getClass().getClassLoader();
	    if (loader == null) {
		enableResolve = true;
		return previous;
	    }
	    throw new SecurityException("Not trusted class");
	} else {
	    enableResolve = false;
	}
	return previous;
    }


    /**
     * The readStreamHeader method is provided to allow subclasses to
     * read and verify their own stream headers. It reads and
     * verifies the magic number and version number.
     * @since     JDK1.1
     */
    protected void readStreamHeader()
	throws IOException, StreamCorruptedException
    {
	short incoming_magic = readShort();
	short incoming_version = readShort();
	if (incoming_magic != STREAM_MAGIC)
	    throw new StreamCorruptedException("InputStream does not contain a serialized object");
	
	if (incoming_version != STREAM_VERSION)
	    throw new StreamCorruptedException("Version Mismatch, Expected " +
					       STREAM_VERSION + " and got " +
					       incoming_version);
    }

    /*
     * Read a ObjectStreamClasss from the stream, it may recursively
     * create another ObjectStreamClass for the superclass it references.
     */
    private ObjectStreamClass inputClassDescriptor()
	throws IOException, InvalidClassException, ClassNotFoundException
    {

	/* Read the class name and hash */
	Class aclass;
	String classname = readUTF(); 
	long hash = readLong();

	/* Read a new class version descriptor from the stream */
	ObjectStreamClass v = new ObjectStreamClass(classname, hash);

	/* Assign the wire handle for this ObjectStreamClass and read it */
	int wireoffset = assignWireOffset(v); 
	v.read(this);

	/* Switch to BlockDataMode and call resolveClass.
	 * It may raise ClassNotFoundException.
	 * Consume any extra data or objects left by resolve class and
	 * read the endOfBlockData. Then switch out of BlockDataMode.
	 */
	boolean prevMode = setBlockData(true);
	try {
	    aclass = resolveClass((ObjectStreamClass)v);
	} catch (ClassNotFoundException e) {
	    /* Not all classes in the serialized stream must be resolvable to
	     * a class in the current VM. The original version of a class need not
	     * resolve a superclass added by an evolved version of the class.
   	     * ClassNotFoundException will be thrown if it is detected elsewhere
	     * that this class would be used as a most derived class.
	     */
	    aclass = null;
 	} catch (NoClassDefFoundError e) {
 	    /* This exception was thrown when looking for an array of class,
 	     * and class could not be found.
 	     */
 	    aclass = null;
	}
	SkipToEndOfBlockData();
	prevMode = setBlockData(prevMode);


	/* Verify that the class returned is "compatible" with
	 * the class description.  i.e. the name and hash match.
	 * Set the class this ObjectStreamClass will use to create 
	 * instances.
	 */
	v.setClass(aclass);

	/* Get the superdescriptor of this one and it set it.
	 */
	ObjectStreamClass superdesc = (ObjectStreamClass)readObject();
	v.setSuperclass(superdesc);

	return v;
    }

    /* Private routine to read in an array. Called from inputObject
     * after the typecode has been read from the stream.
     *
     * @param requireLocalClass If false, do not throw ClassNotFoundException
     *                          when local class does not exist.
     */
    private int inputArray(boolean requireLocalClass)
	throws IOException, ClassNotFoundException
    {
	ObjectStreamClass v = (ObjectStreamClass)readObject();
	Class arrayclass = v.forClass();
	if (arrayclass == null && requireLocalClass)
	    throw new ClassNotFoundException(v.getName());

	/* This can't be done with new because only the top level array
	 * is needed and the type must be set properly.
	 * the lower level arrays will be created when they are read.
	 */
	int length = readInt();
	currentObject = (arrayclass == null) ? 
	    null : allocateNewArray(arrayclass, length);
	int wireoffset = assignWireOffset(currentObject);
	
	/* Read in the values from the array,
	 * It dispatches using the type and read using the read* methods.
	 */
	int i;

	if (arrayclass != null 
	    && arrayclass.getComponentType().isPrimitive()) {
	    Class type = arrayclass.getComponentType();
	    /* Arrays of primitive types read data in blocks and
	     * decode the data types from the buffer.
	     */
	    if (buffer == null)
		buffer = new byte[1024];
	    int offset = buffer.length;
	    int buflen = buffer.length;

	    if (type == Boolean.TYPE) {
		boolean[] array = (boolean[])currentObject;
		for (i = 0; i < length; i++) {
		    if (offset >= buflen) {
			int readlen = Math.min(length-i, buflen);
			readFully(buffer, 0, readlen);
			offset = 0;
		    }
		    array[i] = (buffer[offset] != 0);
		    offset += 1;
		}
	    } else if (type == Byte.TYPE) {
		byte[] array = (byte[])currentObject;
		int ai = 0;
		while (ai < length) {
		    int readlen = Math.min(length-ai, buflen);
		    readFully(buffer, 0, readlen);
		    System.arraycopy(buffer, 0, array, ai, readlen);
		    ai += readlen;
		}
	    } else if (type == Short.TYPE) {
		short[] array = (short[])currentObject;
		for (i = 0; i < length; i++) {
		    if (offset > buflen - 2) {
			int readlen = Math.min((length-i)*2, buflen);
			readFully(buffer, 0, readlen);
			offset = 0;
		    }
		    array[i] = (short)(((buffer[offset] & 0xff) << 8) +
				       ((buffer[offset+1] & 0xff) << 0));
		    offset += 2;
		}
	    } else if (type == Integer.TYPE) {
		int[] array = (int[])currentObject;
		for (i = 0; i < length; i++) {
		    if (offset > buflen - 4) {
			int readlen = Math.min((length-i)*4, buflen);
			readFully(buffer, 0, readlen);
			offset = 0;
		    }
		    array[i] = (((buffer[offset] & 0xff) << 24) +
				((buffer[offset+1] & 0xff) << 16) +
				((buffer[offset+2] & 0xff) << 8) +
				((buffer[offset+3] & 0xff) << 0));
		    offset += 4;
		}
	    } else if (type == Long.TYPE) {
		long[] array = (long[])currentObject;
		for (i = 0; i < length; i++) {
		    if (offset > buflen - 8) {
			int readlen = Math.min((length-i)*8, buflen);
			readFully(buffer, 0, readlen);
			offset = 0;
		    }
		    int upper = (((buffer[offset] & 0xff) << 24) +
				((buffer[offset+1] & 0xff) << 16) +
				((buffer[offset+2] & 0xff) << 8) +
				((buffer[offset+3] & 0xff) << 0));
		    int lower = (((buffer[offset+4] & 0xff) << 24) +
				((buffer[offset+5] & 0xff) << 16) +
				((buffer[offset+6] & 0xff) << 8) +
				((buffer[offset+7] & 0xff) << 0));
		    array[i] = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
		    offset += 8;
		}
	    } else if (type == Float.TYPE) {
		float[] array = (float[])currentObject;
		for (i = 0; i < length; i++) {
		    if (offset > buflen - 4) {
			int readlen = Math.min((length-i)*4, buflen);
			readFully(buffer, 0, readlen);
			offset = 0;
		    }
		    int value = (((buffer[offset] & 0xff) << 24) +
				 ((buffer[offset+1] & 0xff) << 16) +
				 ((buffer[offset+2] & 0xff) << 8) +
				 ((buffer[offset+3] & 0xff) << 0));
		    offset += 4;
		    array[i] = Float.intBitsToFloat(value);
		}
	    } else if (type == Double.TYPE) {
		double[] array = (double[])currentObject;
		for (i = 0; i < length; i++) {

⌨️ 快捷键说明

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