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 + -
显示快捷键?