FileDocCategorySizeDatePackage
ObjectInputStream.javaAPI DocAndroid 1.5 API117962Wed May 06 22:41:04 BST 2009java.io

ObjectInputStream

public class ObjectInputStream extends InputStream implements ObjectStreamConstants, ObjectInput
A specialized {@link InputStream} that is able to read (deserialize) Java objects as well as primitive data types (int, byte, char etc.). The data has typically been saved using an ObjectOutputStream.
see
ObjectOutputStream
see
ObjectInput
see
Serializable
see
Externalizable
since
Android 1.0

Fields Summary
private static InputStream
emptyStream
private static final Object
UNSHARED_OBJ
private boolean
hasPushbackTC
private byte
pushbackTC
private int
nestedLevels
private int
currentHandle
private DataInputStream
input
private DataInputStream
primitiveTypes
private InputStream
primitiveData
private boolean
enableResolve
private Hashtable
objectsRead
private Object
currentObject
private ObjectStreamClass
currentClass
private InputValidationDesc[]
validations
private boolean
subclassOverridingImplementation
private ClassLoader
callerClassLoader
private boolean
mustResolve
private Integer
descriptorHandle
private IdentityHashMap
readResolveCache
private static final Hashtable
PRIMITIVE_CLASSES
private static final ClassLoader
bootstrapLoader
private static final ClassLoader
systemLoader
Constructors Summary
protected ObjectInputStream()
Constructs a new ObjectInputStream. This default constructor can be used by subclasses that do not want to use the public constructor if it allocates unneeded data.

throws
IOException if an error occurs when creating this stream.
throws
SecurityException if a security manager is installed and it denies subclassing this class.
see
SecurityManager#checkPermission(java.security.Permission)
since
Android 1.0

        super();
        SecurityManager currentManager = System.getSecurityManager();
        if (currentManager != null) {
            currentManager.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
        // WARNING - we should throw IOException if not called from a subclass
        // according to the JavaDoc. Add the test.
        this.subclassOverridingImplementation = true;
    
public ObjectInputStream(InputStream input)
Constructs a new ObjectInputStream that reads from the InputStream {@code input}.

param
input the non-null source InputStream to filter reads on.
throws
IOException if an error occurs while reading the stream header.
throws
StreamCorruptedException if the source stream does not contain serialized objects that can be read.
throws
SecurityException if a security manager is installed and it denies subclassing this class.
since
Android 1.0

        final Class<?> implementationClass = getClass();
        final Class<?> thisClass = ObjectInputStream.class;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null && implementationClass != thisClass) {
            boolean mustCheck = (AccessController
                    .doPrivileged(new PrivilegedAction<Boolean>() {
                        public Boolean run() {
                            try {
                                Method method = implementationClass
                                        .getMethod(
                                                "readFields", //$NON-NLS-1$
                                                ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
                                if (method.getDeclaringClass() != thisClass) {
                                    return Boolean.TRUE;
                                }
                            } catch (NoSuchMethodException e) {
                            }
                            try {
                                Method method = implementationClass
                                        .getMethod(
                                                "readUnshared", //$NON-NLS-1$
                                                ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
                                if (method.getDeclaringClass() != thisClass) {
                                    return Boolean.TRUE;
                                }
                            } catch (NoSuchMethodException e) {
                            }
                            return Boolean.FALSE;
                        }
                    })).booleanValue();
            if (mustCheck) {
                sm
                        .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        this.input = (input instanceof DataInputStream) ? (DataInputStream) input
                : new DataInputStream(input);
        primitiveTypes = new DataInputStream(this);
        enableResolve = false;
        this.subclassOverridingImplementation = false;
        this.readResolveCache = new IdentityHashMap<Class<?>, Object>();
        resetState();
        nestedLevels = 0;
        // So read...() methods can be used by
        // subclasses during readStreamHeader()
        primitiveData = this.input;
        // Has to be done here according to the specification
        readStreamHeader();
        primitiveData = emptyStream;
    
Methods Summary
public intavailable()
Returns the number of bytes of primitive data that can be read from this stream without blocking. This method should not be used at any arbitrary position; just when reading primitive data types (int, char etc).

return
the number of available primitive data bytes.
throws
IOException if any I/O problem occurs while computing the available bytes.
since
Android 1.0

        // returns 0 if next data is an object, or N if reading primitive types
        checkReadPrimitiveTypes();
        return primitiveData.available();
    
private voidcheckReadPrimitiveTypes()
Checks to if it is ok to read primitive types from this stream at this point. One is not supposed to read primitive types when about to read an object, for example, so an exception has to be thrown.

throws
IOException If any IO problem occurred when trying to read primitive type or if it is illegal to read primitive types

        // If we still have primitive data, it is ok to read primitive data
        if (primitiveData == input || primitiveData.available() > 0) {
            return;
        }

        // If we got here either we had no Stream previously created or
        // we no longer have data in that one, so get more bytes
        do {
            int next = 0;
            if (hasPushbackTC) {
                hasPushbackTC = false;
            } else {
                next = input.read();
                pushbackTC = (byte) next;
            }
            switch (pushbackTC) {
                case TC_BLOCKDATA:
                    primitiveData = new ByteArrayInputStream(readBlockData());
                    return;
                case TC_BLOCKDATALONG:
                    primitiveData = new ByteArrayInputStream(
                            readBlockDataLong());
                    return;
                case TC_RESET:
                    resetState();
                    break;
                default:
                    if (next != -1) {
                        pushbackTC();
                    }
                    return;
            }
            // Only TC_RESET falls through
        } while (true);
    
private static voidcheckedSetSuperClassDesc(java.io.ObjectStreamClass desc, java.io.ObjectStreamClass superDesc)

        if (desc.equals(superDesc)) {
            throw new StreamCorruptedException();
        }
        desc.setSuperclass(superDesc);
    
public voidclose()
Closes this stream. This implementation closes the source stream.

throws
IOException if an error occurs while closing this stream.
since
Android 1.0

        input.close();
    
public voiddefaultReadObject()
Default method to read objects from this stream. Serializable fields defined in the object's class and superclasses are read from the source stream.

throws
ClassNotFoundException if the object's class cannot be found.
throws
IOException if an I/O error occurs while reading the object data.
throws
NotActiveException if this method is not called from {@code readObject()}.
see
ObjectOutputStream#defaultWriteObject
since
Android 1.0

        // We can't be called from just anywhere. There are rules.
        if (currentObject != null || !mustResolve) {
            readFieldValues(currentObject, currentClass);
        } else {
            throw new NotActiveException();
        }
    
private voiddiscardData()
Reads and discards block data and objects until TC_ENDBLOCKDATA is found.

throws
IOException If an IO exception happened when reading the optional class annotation.
throws
ClassNotFoundException If the class corresponding to the class descriptor could not be found.

        primitiveData = emptyStream;
        boolean resolve = mustResolve;
        mustResolve = false;
        do {
            byte tc = nextTC();
            if (tc == TC_ENDBLOCKDATA) {
                mustResolve = resolve;
                return; // End of annotation
            }
            readContent(tc);
        } while (true);
    
protected booleanenableResolveObject(boolean enable)
Enables object replacement for this stream. By default this is not enabled. Only trusted subclasses (loaded with system class loader) are allowed to change this status.

param
enable {@code true} to enable object replacement; {@code false} to disable it.
return
the previous setting.
throws
SecurityException if a security manager is installed and it denies enabling object replacement for this stream.
see
#resolveObject
see
ObjectOutputStream#enableReplaceObject
since
Android 1.0

        if (enable) {
            // The Stream has to be trusted for this feature to be enabled.
            // trusted means the stream's classloader has to be null
            SecurityManager currentManager = System.getSecurityManager();
            if (currentManager != null) {
                currentManager.checkPermission(SUBSTITUTION_PERMISSION);
            }
        }
        boolean originalValue = enableResolve;
        enableResolve = enable;
        return originalValue;
    
private intfindStreamSuperclass(java.lang.Class cl, java.util.ArrayList classList, int lastIndex)

        ObjectStreamClass objCl;
        String forName;

        for (int i = lastIndex; i < classList.size(); i++) {
            objCl = classList.get(i);
            forName = objCl.forClass().getName();

            if (objCl.getName().equals(forName)) {
                if (cl.getName().equals(objCl.getName())) {
                    return i;
                }
            } else {
                // there was a class replacement
                if (cl.getName().equals(forName)) {
                    return i;
                }
            }
        }
        return -1;
    
private static java.lang.StringgetBaseName(java.lang.String fullName)

        int k = fullName.lastIndexOf("."); //$NON-NLS-1$

        if (k == -1 || k == (fullName.length() - 1)) {
            return fullName;
        }
        return fullName.substring(k + 1);
    
private static java.lang.ClassLoadergetClosestUserClassLoader()
Searches up the call stack to find the closest user-defined class loader.

return
a user-defined class loader or null if one isn't found


                                
        
        Class<?>[] stackClasses = VMStack.getClasses(-1, false);
        for (Class<?> stackClass : stackClasses) {
            ClassLoader loader = stackClass.getClassLoader();
            if (loader != null && loader != bootstrapLoader
                    && loader != systemLoader) {
                return loader;
            }
        }
        return null;
    
private booleaninSamePackage(java.lang.Class c1, java.lang.Class c2)
Checks if two classes belong to the same package.

param
c1 one of the classes to test.
param
c2 the other class to test.
return
{@code true} if the two classes belong to the same package, {@code false} otherwise.

        String nameC1 = c1.getName();
        String nameC2 = c2.getName();
        int indexDotC1 = nameC1.lastIndexOf('.");
        int indexDotC2 = nameC2.lastIndexOf('.");
        // BEGIN android-changed
        // copied from newer version of harmony
        if (indexDotC1 != indexDotC2) {
            return false; // cannot be in the same package if indices are not
        }
        // END android-changed
        // the same
        if (indexDotC1 < 0) {
            return true; // both of them are in default package
        }
        return nameC1.substring(0, indexDotC1).equals(
                nameC2.substring(0, indexDotC2));
    
private static native java.lang.ObjectnewInstance(java.lang.Class instantiationClass, java.lang.Class constructorClass)
Create and return a new instance of class {@code instantiationClass} but running the constructor defined in class {@code constructorClass} (same as {@code instantiationClass} or a superclass). Has to be native to avoid visibility rules and to be able to have {@code instantiationClass} not the same as {@code constructorClass} (no such API in java.lang.reflect).

param
instantiationClass The new object will be an instance of this class
param
constructorClass The empty constructor to run will be in this class
return
the object created from {@code instantiationClass}

private intnextHandle()
Return the next {@code int} handle to be used to indicate cyclic references being loaded from the stream.

return
the next handle to represent the next cyclic reference

        return this.currentHandle++;
    
private bytenextTC()
Return the next token code (TC) from the receiver, which indicates what kind of object follows

return
the next TC from the receiver
throws
IOException If an IO error occurs
see
ObjectStreamConstants

        if (hasPushbackTC) {
            hasPushbackTC = false; // We are consuming it
        } else {
            // Just in case a later call decides to really push it back,
            // we don't require the caller to pass it as parameter
            pushbackTC = input.readByte();
        }
        return pushbackTC;
    
private static native voidobjSetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, java.lang.String fieldTypeName, java.lang.Object value)
Set a given declared field named {@code fieldName} of {@code instance} to the new value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass Class which declares the field
param
fieldName Name of the field to set
param
fieldTypeName Name of the class defining the type of the field
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private voidpushbackTC()
Pushes back the last TC code read

        hasPushbackTC = true;
    
public intread()
Reads a single byte from the source stream and returns it as an integer in the range from 0 to 255. Returns -1 if the end of the source stream has been reached. Blocks if no input is available.

return
the byte read or -1 if the end of the source stream has been reached.
throws
IOException if an error occurs while reading from this stream.
since
Android 1.0

        checkReadPrimitiveTypes();
        return primitiveData.read();
    
public intread(byte[] buffer, int offset, int length)
Reads at most {@code length} bytes from the source stream and stores them in byte array {@code buffer} starting at offset {@code count}. Blocks until {@code count} bytes have been read, the end of the source stream is detected or an exception is thrown.

param
buffer the array in which to store the bytes read.
param
offset the initial position in {@code buffer} to store the bytes read from the source stream.
param
length the maximum number of bytes to store in {@code buffer}.
return
the number of bytes read or -1 if the end of the source input stream has been reached.
throws
IndexOutOfBoundsException if {@code offset < 0} or {@code length < 0}, or if {@code offset + length} is greater than the length of {@code buffer}.
throws
IOException if an error occurs while reading from this stream.
throws
NullPointerException if {@code buffer} is {@code null}.
since
Android 1.0

        // BEGIN android-changed
        if (buffer == null) {
            throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
        }
        // avoid int overflow
        // Exception priorities (in case of multiple errors) differ from
        // RI, but are spec-compliant.
        // removed redundant check, used (offset | length) < 0 instead of
        // (offset < 0) || (length < 0) to safe one operation
        if ((offset | length) < 0 || length > buffer.length - offset) {
            throw new ArrayIndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
        }
        // END android-changed
        if (length == 0) {
            return 0;
        }
        checkReadPrimitiveTypes();
        return primitiveData.read(buffer, offset, length);
    
private byte[]readBlockData()
Reads and returns an array of raw bytes with primitive data. The array will have up to 255 bytes. The primitive data will be in the format described by {@code DataOutputStream}.

return
The primitive data read, as raw bytes
throws
IOException If an IO exception happened when reading the primitive data.

        byte[] result = new byte[input.readByte() & 0xff];
        input.readFully(result);
        return result;
    
private byte[]readBlockDataLong()
Reads and returns an array of raw bytes with primitive data. The array will have more than 255 bytes. The primitive data will be in the format described by {@code DataOutputStream}.

return
The primitive data read, as raw bytes
throws
IOException If an IO exception happened when reading the primitive data.

        byte[] result = new byte[input.readInt()];
        input.readFully(result);
        return result;
    
public booleanreadBoolean()
Reads a boolean from the source stream.

return
the boolean value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readBoolean();
    
public bytereadByte()
Reads a byte (8 bit) from the source stream.

return
the byte value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readByte();
    
public charreadChar()
Reads a character (16 bit) from the source stream.

return
the char value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readChar();
    
private java.io.ObjectStreamClassreadClassDesc()
Reads a class descriptor (an {@code ObjectStreamClass}) from the stream.

return
the class descriptor read from the stream
throws
IOException If an IO exception happened when reading the class descriptor.
throws
ClassNotFoundException If the class corresponding to the class descriptor could not be found.

        byte tc = nextTC();
        switch (tc) {
            case TC_CLASSDESC:
                return readNewClassDesc(false);
            case TC_PROXYCLASSDESC:
                Class<?> proxyClass = readNewProxyClassDesc();
                ObjectStreamClass streamClass = ObjectStreamClass
                        .lookup(proxyClass);
                streamClass.setLoadFields(new ObjectStreamField[0]);
                registerObjectRead(streamClass, Integer.valueOf(nextHandle()),
                        false);
                checkedSetSuperClassDesc(streamClass, readClassDesc());
                return streamClass;
            case TC_REFERENCE:
                return (ObjectStreamClass) readCyclicReference();
            case TC_NULL:
                return null;
            default:
                throw new StreamCorruptedException(Msg.getString(
                        "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
        }
    
protected java.io.ObjectStreamClassreadClassDescriptor()
Reads a class descriptor from the source stream.

return
the class descriptor read from the source stream.
throws
ClassNotFoundException if a class for one of the objects cannot be found.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0


        ObjectStreamClass newClassDesc = new ObjectStreamClass();
        String name = input.readUTF();
        if ("".equals(name)) {
            throw new IOException("The stream is corrupted.");
        }
        newClassDesc.setName(name);
        newClassDesc.setSerialVersionUID(input.readLong());
        newClassDesc.setFlags(input.readByte());

        // We must register the class descriptor before reading field
        // descriptors.
        // if called outside of readObject, the descriptorHandle might be null
        descriptorHandle = (null == descriptorHandle ? Integer
                .valueOf(nextHandle()) : descriptorHandle);
        registerObjectRead(newClassDesc, descriptorHandle, false);
        descriptorHandle = null;

        readFieldDescriptors(newClassDesc);
        return newClassDesc;
    
private java.lang.ObjectreadContent(byte tc)
Reads the content of the receiver based on the previously read token {@code tc}.

param
tc The token code for the next item in the stream
return
the object read from the stream
throws
IOException If an IO exception happened when reading the class descriptor.
throws
ClassNotFoundException If the class corresponding to the object being read could not be found.

        switch (tc) {
            case TC_BLOCKDATA:
                return readBlockData();
            case TC_BLOCKDATALONG:
                return readBlockDataLong();
            case TC_CLASS:
                return readNewClass(false);
            case TC_CLASSDESC:
                return readNewClassDesc(false);
            case TC_ARRAY:
                return readNewArray(false);
            case TC_OBJECT:
                return readNewObject(false);
            case TC_STRING:
                return readNewString(false);
            case TC_LONGSTRING:
                return readNewLongString(false);
            case TC_REFERENCE:
                return readCyclicReference();
            case TC_NULL:
                return null;
            case TC_EXCEPTION:
                Exception exc = readException();
                throw new WriteAbortedException(Msg.getString("K00d3"), exc); //$NON-NLS-1$
            case TC_RESET:
                resetState();
                return null;
            default:
                throw new StreamCorruptedException(Msg.getString(
                        "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
        }
    
private java.lang.ObjectreadCyclicReference()
Reads the next item from the stream assuming it is a cyclic reference to an object previously read. Return the actual object previously read.

return
the object previously read from the stream
throws
IOException If an IO exception happened when reading the class descriptor.
throws
InvalidObjectException If the cyclic reference is not valid.

        return registeredObjectRead(readNewHandle());
    
public doublereadDouble()
Reads a double (64 bit) from the source stream.

return
the double value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readDouble();
    
private java.lang.ObjectreadEnum(boolean unshared)

        // read classdesc for Enum first
        ObjectStreamClass classDesc = readEnumDesc();
        Integer newHandle = Integer.valueOf(nextHandle());
        // read name after class desc
        String name;
        byte tc = nextTC();
        switch (tc) {
            case TC_REFERENCE:
                if (unshared) {
                    readNewHandle();
                    throw new InvalidObjectException(Msg.getString("KA002")); //$NON-NLS-1$
                }
                name = (String) readCyclicReference();
                break;
            case TC_STRING:
                name = (String) readNewString(unshared);
                break;
            default:
                throw new StreamCorruptedException(Msg.getString("K00d2"));//$NON-NLS-1$
        }

        Enum<?> result = Enum.valueOf((Class) classDesc.forClass(), name);
        registerObjectRead(result, newHandle, unshared);

        return result;
    
private java.io.ObjectStreamClassreadEnumDesc()

        byte tc = nextTC();
        switch (tc) {
            case TC_CLASSDESC:
                return readEnumDescInternal();
            case TC_REFERENCE:
                return (ObjectStreamClass) readCyclicReference();
            case TC_NULL:
                return null;
            default:
                throw new StreamCorruptedException(Msg.getString(
                        "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
        }
    
private java.io.ObjectStreamClassreadEnumDescInternal()

        ObjectStreamClass classDesc;
        primitiveData = input;
        Integer oldHandle = descriptorHandle;
        descriptorHandle = Integer.valueOf(nextHandle());
        classDesc = readClassDescriptor();
        if (descriptorHandle != null) {
            registerObjectRead(classDesc, descriptorHandle, false);
        }
        descriptorHandle = oldHandle;
        primitiveData = emptyStream;
        classDesc.setClass(resolveClass(classDesc));
        // Consume unread class annotation data and TC_ENDBLOCKDATA
        discardData();
        ObjectStreamClass superClass = readClassDesc();
        checkedSetSuperClassDesc(classDesc, superClass);
        // Check SUIDs, note all SUID for Enum is 0L
        if (0L != classDesc.getSerialVersionUID()
                || 0L != superClass.getSerialVersionUID()) {
            throw new InvalidClassException(superClass.getName(), Msg
                    .getString("K00da", superClass, //$NON-NLS-1$
                            superClass));
        }
        byte tc = nextTC();
        // discard TC_ENDBLOCKDATA after classDesc if any
        if (tc == TC_ENDBLOCKDATA) {
            // read next parent class. For enum, it may be null
            superClass.setSuperclass(readClassDesc());
        } else {
            // not TC_ENDBLOCKDATA, push back for next read
            pushbackTC();
        }
        return classDesc;
    
private java.lang.ExceptionreadException()
Read the next item assuming it is an exception. The exception is not a regular instance in the object graph, but the exception instance that happened (if any) when dumping the original object graph. The set of seen objects will be reset just before and just after loading this exception object.

When exceptions are found normally in the object graph, they are loaded as a regular object, and not by this method. In that case, the set of "known objects" is not reset.

return
the exception read
throws
IOException If an IO exception happened when reading the exception object.
throws
ClassNotFoundException If a class could not be found when reading the object graph for the exception
throws
OptionalDataException If optional data could not be found when reading the exception graph
throws
WriteAbortedException If another exception was caused when dumping this exception


        resetSeenObjects();

        // Now we read the Throwable object that was saved
        // WARNING - the grammar says it is a Throwable, but the
        // WriteAbortedException constructor takes an Exception. So, we read an
        // Exception from the stream
        Exception exc = (Exception) readObject();

        // We reset the receiver's state (the grammar has "reset" in normal
        // font)
        resetSeenObjects();
        return exc;
    
private voidreadFieldDescriptors(java.io.ObjectStreamClass cDesc)
Reads a collection of field descriptors (name, type name, etc) for the class descriptor {@code cDesc} (an {@code ObjectStreamClass})

param
cDesc The class descriptor (an {@code ObjectStreamClass}) for which to write field information
throws
IOException If an IO exception happened when reading the field descriptors.
throws
ClassNotFoundException If a class for one of the field types could not be found
see
#readObject()

        short numFields = input.readShort();
        ObjectStreamField[] fields = new ObjectStreamField[numFields];

        // We set it now, but each element will be inserted in the array further
        // down
        cDesc.setLoadFields(fields);

        // Check ObjectOutputStream.writeFieldDescriptors
        for (short i = 0; i < numFields; i++) {
            char typecode = (char) input.readByte();
            String fieldName = input.readUTF();
            boolean isPrimType = ObjectStreamClass.isPrimitiveType(typecode);
            String classSig;
            if (isPrimType) {
                classSig = String.valueOf(typecode);
            } else {
                // The spec says it is a UTF, but experience shows they dump
                // this String using writeObject (unlike the field name, which
                // is saved with writeUTF).
                // And if resolveObject is enabled, the classSig may be modified
                // so that the original class descriptor cannot be read
                // properly, so it is disabled.
                boolean old = enableResolve;
                try {
                    enableResolve = false;
                    classSig = (String) readObject();
                } finally {
                    enableResolve = old;
                }
            }
            ObjectStreamField f = new ObjectStreamField(classSig, fieldName);
            fields[i] = f;
        }
    
private voidreadFieldValues(EmulatedFieldsForLoading emulatedFields)
Reads a collection of field values for the emulated fields {@code emulatedFields}

param
emulatedFields an {@code EmulatedFieldsForLoading}, concrete subclass of {@code GetField}
throws
IOException If an IO exception happened when reading the field values.
throws
InvalidClassException If an incompatible type is being assigned to an emulated field.
throws
OptionalDataException If optional data could not be found when reading the exception graph
see
#readFields
see
#readObject()

        EmulatedFields.ObjectSlot[] slots = emulatedFields.emulatedFields()
                .slots();
        for (ObjectSlot element : slots) {
            element.defaulted = false;
            Class<?> type = element.field.getType();
            if (type == Integer.TYPE) {
                element.fieldValue = Integer.valueOf(input.readInt());
            } else if (type == Byte.TYPE) {
                element.fieldValue = Byte.valueOf(input.readByte());
            } else if (type == Character.TYPE) {
                element.fieldValue = Character.valueOf(input.readChar());
            } else if (type == Short.TYPE) {
                element.fieldValue = Short.valueOf(input.readShort());
            } else if (type == Boolean.TYPE) {
                element.fieldValue = Boolean.valueOf(input.readBoolean());
            } else if (type == Long.TYPE) {
                element.fieldValue = Long.valueOf(input.readLong());
            } else if (type == Float.TYPE) {
                element.fieldValue = Float.valueOf(input.readFloat());
            } else if (type == Double.TYPE) {
                element.fieldValue = Double.valueOf(input.readDouble());
            } else {
                // Either array or Object
                try {
                    element.fieldValue = readObject();
                } catch (ClassNotFoundException cnf) {
                    // WARNING- Not sure this is the right thing to do. Write
                    // test case.
                    throw new InvalidClassException(cnf.toString());
                }
            }
        }
    
private voidreadFieldValues(java.lang.Object obj, java.io.ObjectStreamClass classDesc)
Reads a collection of field values for the class descriptor {@code classDesc} (an {@code ObjectStreamClass}). The values will be used to set instance fields in object {@code obj}. This is the default mechanism, when emulated fields (an {@code GetField}) are not used. Actual values to load are stored directly into the object {@code obj}.

param
obj Instance in which the fields will be set.
param
classDesc A class descriptor (an {@code ObjectStreamClass}) defining which fields should be loaded.
throws
IOException If an IO exception happened when reading the field values.
throws
InvalidClassException If an incompatible type is being assigned to an emulated field.
throws
OptionalDataException If optional data could not be found when reading the exception graph
throws
ClassNotFoundException If a class of an object being de-serialized can not be found
see
#readFields
see
#readObject()

        // Now we must read all fields and assign them to the receiver
        ObjectStreamField[] fields = classDesc.getLoadFields();
        fields = (null == fields ? new ObjectStreamField[] {} : fields);
        Class<?> declaringClass = classDesc.forClass();
        if (declaringClass == null && mustResolve) {
            throw new ClassNotFoundException(classDesc.getName());
        }

        for (ObjectStreamField fieldDesc : fields) {
            // Code duplication starts, just because Java is typed
            if (fieldDesc.isPrimitive()) {
                try {
                    switch (fieldDesc.getTypeCode()) {
                        case 'B":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readByte());
                            break;
                        case 'C":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readChar());
                            break;
                        case 'D":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readDouble());
                            break;
                        case 'F":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readFloat());
                            break;
                        case 'I":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readInt());
                            break;
                        case 'J":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readLong());
                            break;
                        case 'S":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readShort());
                            break;
                        case 'Z":
                            setField(obj, declaringClass, fieldDesc.getName(),
                                    input.readBoolean());
                            break;
                        default:
                            throw new StreamCorruptedException(Msg.getString(
                                    "K00d5", fieldDesc.getTypeCode())); //$NON-NLS-1$
                    }
                } catch (NoSuchFieldError err) {
                }
            } else {
                // Object type (array included).
                String fieldName = fieldDesc.getName();
                boolean setBack = false;
                ObjectStreamField field = classDesc.getField(fieldName);
                if (mustResolve && field == null) {
                    setBack = true;
                    mustResolve = false;
                }
                Object toSet;
                if (field != null && field.isUnshared()) {
                    toSet = readUnshared();
                } else {
                    toSet = readObject();
                }
                if (setBack) {
                    mustResolve = true;
                }
                if (field != null) {
                    if (toSet != null) {
                        // BEGIN android-removed
                        // Class<?> fieldType = field.getType();
                        // END android-removed
                        // BEGIN android-added
                        // Originally getTypeInternal() was called getType().
                        // After the semantics of getType() changed inside
                        // Harmony, the check below wasn't adjusted and didn't
                        // work anymore.
                        Class<?> fieldType = field.getTypeInternal();
                        // END android-added                        
                        Class<?> valueType = toSet.getClass();
                        if (!fieldType.isAssignableFrom(valueType)) {
                            throw new ClassCastException(Msg.getString(
                                    "K00d4", new String[] { //$NON-NLS-1$
                                    fieldType.toString(), valueType.toString(),
                                            classDesc.getName() + "." //$NON-NLS-1$
                                                    + fieldName }));
                        }
                        try {
                            objSetField(obj, declaringClass, fieldName, field
                                    .getTypeString(), toSet);
                        } catch (NoSuchFieldError e) {
                            // Ignored
                        }
                    }
                }
            }
        }
    
public java.io.ObjectInputStream$GetFieldreadFields()
Reads the persistent fields of the object that is currently being read from the source stream. The values read are stored in a GetField object that provides access to the persistent fields. This GetField object is then returned.

return
the GetField object from which persistent fields can be accessed by name.
throws
ClassNotFoundException if the class of an object being deserialized can not be found.
throws
IOException if an error occurs while reading from this stream.
throws
NotActiveException if this stream is currently not reading an object.
since
Android 1.0

        // We can't be called from just anywhere. There are rules.
        if (currentObject == null) {
            throw new NotActiveException();
        }
        EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(
                currentClass);
        readFieldValues(result);
        return result;
    
public floatreadFloat()
Reads a float (32 bit) from the source stream.

return
the float value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readFloat();
    
public voidreadFully(byte[] buffer)
Reads bytes from the source stream into the byte array {@code buffer}. This method will block until {@code buffer.length} bytes have been read.

param
buffer the array in which to store the bytes read.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        primitiveTypes.readFully(buffer);
    
public voidreadFully(byte[] buffer, int offset, int length)
Reads bytes from the source stream into the byte array {@code buffer}. This method will block until {@code length} number of bytes have been read.

param
buffer the byte array in which to store the bytes read.
param
offset the initial position in {@code buffer} to store the bytes read from the source stream.
param
length the maximum number of bytes to store in {@code buffer}.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        primitiveTypes.readFully(buffer, offset, length);
    
private voidreadHierarchy(java.lang.Object object, java.io.ObjectStreamClass classDesc)
Walks the hierarchy of classes described by class descriptor {@code classDesc} and reads the field values corresponding to fields declared by the corresponding class descriptor. The instance to store field values into is {@code object}. If the class (corresponding to class descriptor {@code classDesc}) defines private instance method {@code readObject} it will be used to load field values.

param
object Instance into which stored field values loaded.
param
classDesc A class descriptor (an {@code ObjectStreamClass}) defining which fields should be loaded.
throws
IOException If an IO exception happened when reading the field values in the hierarchy.
throws
ClassNotFoundException If a class for one of the field types could not be found
throws
NotActiveException If {@code defaultReadObject} is called from the wrong context.
see
#defaultReadObject
see
#readObject()

        // We can't be called from just anywhere. There are rules.
        if (object == null && mustResolve) {
            throw new NotActiveException();
        }

        ArrayList<ObjectStreamClass> streamClassList = new ArrayList<ObjectStreamClass>(
                32);
        ObjectStreamClass nextStreamClass = classDesc;
        while (nextStreamClass != null) {
            streamClassList.add(0, nextStreamClass);
            nextStreamClass = nextStreamClass.getSuperclass();
        }
        if (object == null) {
            Iterator<ObjectStreamClass> streamIt = streamClassList.iterator();
            while (streamIt.hasNext()) {
                ObjectStreamClass streamClass = streamIt.next();
                readObjectForClass(null, streamClass);
            }
        } else {
            ArrayList<Class<?>> classList = new ArrayList<Class<?>>(32);
            Class<?> nextClass = object.getClass();
            while (nextClass != null) {
                Class<?> testClass = nextClass.getSuperclass();
                if (testClass != null) {
                    classList.add(0, nextClass);
                }
                nextClass = testClass;
            }
            int lastIndex = 0;
            for (int i = 0; i < classList.size(); i++) {
                Class<?> superclass = classList.get(i);
                int index = findStreamSuperclass(superclass, streamClassList,
                        lastIndex);
                if (index == -1) {
                    readObjectNoData(object, superclass);
                } else {
                    for (int j = lastIndex; j <= index; j++) {
                        readObjectForClass(object, streamClassList.get(j));
                    }
                    lastIndex = index + 1;
                }
            }
        }
    
public intreadInt()
Reads an integer (32 bit) from the source stream.

return
the integer value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readInt();
    
public java.lang.StringreadLine()
Reads the next line from the source stream. Lines are terminated by {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}.

return
the string read from the source stream.
throws
IOException if an error occurs while reading from the source stream.
deprecated
Use {@link BufferedReader}
since
Android 1.0

        return primitiveTypes.readLine();
    
public longreadLong()
Reads a long (64 bit) from the source stream.

return
the long value read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readLong();
    
private java.lang.ObjectreadNewArray(boolean unshared)
Read a new array from the receiver. It is assumed the array has not been read yet (not a cyclic reference). Return the array read.

param
unshared read the object unshared
return
the array read
throws
IOException If an IO exception happened when reading the array.
throws
ClassNotFoundException If a class for one of the objects could not be found
throws
OptionalDataException If optional data could not be found when reading the array.

        ObjectStreamClass classDesc = readClassDesc();

        if (classDesc == null) {
            throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
        }

        Integer newHandle = Integer.valueOf(nextHandle());

        // Array size
        int size = input.readInt();
        Class<?> arrayClass = classDesc.forClass();
        Class<?> componentType = arrayClass.getComponentType();
        Object result = Array.newInstance(componentType, size);

        registerObjectRead(result, newHandle, unshared);

        // Now we have code duplication just because Java is typed. We have to
        // read N elements and assign to array positions, but we must typecast
        // the array first, and also call different methods depending on the
        // elements.
        if (componentType.isPrimitive()) {
            if (componentType == Integer.TYPE) {
                int[] intArray = (int[]) result;
                for (int i = 0; i < size; i++) {
                    intArray[i] = input.readInt();
                }
            } else if (componentType == Byte.TYPE) {
                byte[] byteArray = (byte[]) result;
                input.readFully(byteArray, 0, size);
            } else if (componentType == Character.TYPE) {
                char[] charArray = (char[]) result;
                for (int i = 0; i < size; i++) {
                    charArray[i] = input.readChar();
                }
            } else if (componentType == Short.TYPE) {
                short[] shortArray = (short[]) result;
                for (int i = 0; i < size; i++) {
                    shortArray[i] = input.readShort();
                }
            } else if (componentType == Boolean.TYPE) {
                boolean[] booleanArray = (boolean[]) result;
                for (int i = 0; i < size; i++) {
                    booleanArray[i] = input.readBoolean();
                }
            } else if (componentType == Long.TYPE) {
                long[] longArray = (long[]) result;
                for (int i = 0; i < size; i++) {
                    longArray[i] = input.readLong();
                }
            } else if (componentType == Float.TYPE) {
                float[] floatArray = (float[]) result;
                for (int i = 0; i < size; i++) {
                    floatArray[i] = input.readFloat();
                }
            } else if (componentType == Double.TYPE) {
                double[] doubleArray = (double[]) result;
                for (int i = 0; i < size; i++) {
                    doubleArray[i] = input.readDouble();
                }
            } else {
                throw new ClassNotFoundException(Msg.getString(
                        "K00d7", classDesc.getName())); //$NON-NLS-1$
            }
        } else {
            // Array of Objects
            Object[] objectArray = (Object[]) result;
            for (int i = 0; i < size; i++) {
                objectArray[i] = readObject();
            }
        }
        if (enableResolve) {
            result = resolveObject(result);
            registerObjectRead(result, newHandle, false);
        }
        return result;
    
private java.lang.ClassreadNewClass(boolean unshared)
Reads a new class from the receiver. It is assumed the class has not been read yet (not a cyclic reference). Return the class read.

param
unshared read the object unshared
return
The {@code java.lang.Class} read from the stream.
throws
IOException If an IO exception happened when reading the class.
throws
ClassNotFoundException If a class for one of the objects could not be found

        ObjectStreamClass classDesc = readClassDesc();

        if (classDesc != null) {
            Integer newHandle = Integer.valueOf(nextHandle());
            Class<?> localClass = classDesc.forClass();
            if (localClass != null) {
                registerObjectRead(localClass, newHandle, unshared);
            }
            return localClass;
        }
        throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
    
private java.io.ObjectStreamClassreadNewClassDesc(boolean unshared)
Reads a new class descriptor from the receiver. It is assumed the class descriptor has not been read yet (not a cyclic reference). Return the class descriptor read.

param
unshared read the object unshared
return
The {@code ObjectStreamClass} read from the stream.
throws
IOException If an IO exception happened when reading the class descriptor.
throws
ClassNotFoundException If a class for one of the objects could not be found

        // So read...() methods can be used by
        // subclasses during readClassDescriptor()
        primitiveData = input;
        Integer oldHandle = descriptorHandle;
        descriptorHandle = Integer.valueOf(nextHandle());
        ObjectStreamClass newClassDesc = readClassDescriptor();
        if (descriptorHandle != null) {
            registerObjectRead(newClassDesc, descriptorHandle, unshared);
        }
        descriptorHandle = oldHandle;
        primitiveData = emptyStream;

        // We need to map classDesc to class.
        try {
            newClassDesc.setClass(resolveClass(newClassDesc));
            // Check SUIDs
            verifySUID(newClassDesc);
            // Check base name of the class
            verifyBaseName(newClassDesc);
        } catch (ClassNotFoundException e) {
            if (mustResolve) {
                throw e;
                // Just continue, the class may not be required
            }
        }

        // Resolve the field signatures using the class loader of the
        // resolved class
        ObjectStreamField[] fields = newClassDesc.getLoadFields();
        fields = (null == fields ? new ObjectStreamField[] {} : fields);
        ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
                : newClassDesc.forClass().getClassLoader();
        for (ObjectStreamField element : fields) {
            element.resolve(loader);
        }

        // Consume unread class annotation data and TC_ENDBLOCKDATA
        discardData();
        checkedSetSuperClassDesc(newClassDesc, readClassDesc());
        return newClassDesc;
    
private java.lang.IntegerreadNewHandle()
Write a new handle describing a cyclic reference from the stream.

return
the handle read
throws
IOException If an IO exception happened when reading the handle

        return Integer.valueOf(input.readInt());
    
private java.lang.ObjectreadNewLongString(boolean unshared)
Read a new String in UTF format from the receiver. Return the string read.

param
unshared read the object unshared
return
the string just read.
throws
IOException If an IO exception happened when reading the String.

        long length = input.readLong();
        Object result = input.decodeUTF((int) length);
        if (enableResolve) {
            result = resolveObject(result);
        }
        int newHandle = nextHandle();
        registerObjectRead(result, Integer.valueOf(newHandle), unshared);

        return result;
    
private java.lang.ObjectreadNewObject(boolean unshared)
Read a new object from the stream. It is assumed the object has not been loaded yet (not a cyclic reference). Return the object read. If the object implements {@code Externalizable} its {@code readExternal} is called. Otherwise, all fields described by the class hierarchy are loaded. Each class can define how its declared instance fields are loaded by defining a private method {@code readObject}

param
unshared read the object unshared
return
the object read
throws
IOException If an IO exception happened when reading the object.
throws
OptionalDataException If optional data could not be found when reading the object graph
throws
ClassNotFoundException If a class for one of the objects could not be found

        ObjectStreamClass classDesc = readClassDesc();

        if (classDesc == null) {
            throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
        }

        Integer newHandle = Integer.valueOf(nextHandle());

        // Note that these values come from the Stream, and in fact it could be
        // that the classes have been changed so that the info below now
        // conflicts with the newer class
        boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) > 0;
        boolean wasSerializable = (classDesc.getFlags() & SC_SERIALIZABLE) > 0;

        // Maybe we should cache the values above in classDesc ? It may be the
        // case that when reading classDesc we may need to read more stuff
        // depending on the values above
        Class<?> objectClass = classDesc.forClass();

        Object result, registeredResult = null;
        if (objectClass != null) {
            // The class of the instance may not be the same as the class of the
            // constructor to run
            // This is the constructor to run if Externalizable
            Class<?> constructorClass = objectClass;

            // WARNING - What if the object is serializable and externalizable ?
            // Is that possible ?
            if (wasSerializable) {
                // Now we must run the constructor of the class just above the
                // one that implements Serializable so that slots that were not
                // dumped can be initialized properly
                while (constructorClass != null
                        && ObjectStreamClass.isSerializable(constructorClass)) {
                    constructorClass = constructorClass.getSuperclass();
                }
            }

            // Fetch the empty constructor, or null if none.
            Constructor<?> constructor = null;
            if (constructorClass != null) {
                try {
                    constructor = constructorClass
                            .getDeclaredConstructor(ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
                } catch (NoSuchMethodException nsmEx) {
                    // Ignored
                }
            }

            // Has to have an empty constructor
            if (constructor == null) {
                throw new InvalidClassException(constructorClass.getName(), Msg
                        .getString("K00dc")); //$NON-NLS-1$
            }

            int constructorModifiers = constructor.getModifiers();

            // Now we must check if the empty constructor is visible to the
            // instantiation class
            if (Modifier.isPrivate(constructorModifiers)
                    || (wasExternalizable && !Modifier
                            .isPublic(constructorModifiers))) {
                throw new InvalidClassException(constructorClass.getName(), Msg
                        .getString("K00dc")); //$NON-NLS-1$
            }

            // We know we are testing from a subclass, so the only other case
            // where the visibility is not allowed is when the constructor has
            // default visibility and the instantiation class is in a different
            // package than the constructor class
            if (!Modifier.isPublic(constructorModifiers)
                    && !Modifier.isProtected(constructorModifiers)) {
                // Not public, not private and not protected...means default
                // visibility. Check if same package
                if (!inSamePackage(constructorClass, objectClass)) {
                    throw new InvalidClassException(constructorClass.getName(),
                            Msg.getString("K00dc")); //$NON-NLS-1$
                }
            }

            // Now we know which class to instantiate and which constructor to
            // run. We are allowed to run the constructor.
            result = newInstance(objectClass, constructorClass);
            registerObjectRead(result, newHandle, unshared);

            registeredResult = result;
        } else {
            result = null;
        }

        try {
            // This is how we know what to do in defaultReadObject. And it is
            // also used by defaultReadObject to check if it was called from an
            // invalid place. It also allows readExternal to call
            // defaultReadObject and have it work.
            currentObject = result;
            currentClass = classDesc;

            // If Externalizable, just let the object read itself
            if (wasExternalizable) {
                boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) > 0;
                if (!blockData) {
                    primitiveData = input;
                }
                if (mustResolve) {
                    Externalizable extern = (Externalizable) result;
                    extern.readExternal(this);
                }
                if (blockData) {
                    // Similar to readHierarchy. Anything not read by
                    // readExternal has to be consumed here
                    discardData();
                } else {
                    primitiveData = emptyStream;
                }
            } else {
                // If we got here, it is Serializable but not Externalizable.
                // Walk the hierarchy reading each class' slots
                readHierarchy(result, classDesc);
            }
        } finally {
            // Cleanup, needs to run always so that we can later detect invalid
            // calls to defaultReadObject
            currentObject = null;
            currentClass = null;
        }

        if (objectClass != null) {
            Object readResolveMethod = readResolveCache.get(objectClass);
            if (readResolveMethod != this) {
                if (readResolveMethod == null) {
                    final Method readResolve = ObjectStreamClass
                            .methodReadResolve(objectClass);
                    if (readResolve == null) {
                        readResolveCache.put(objectClass, this);
                        readResolveMethod = null;
                    } else {
                        // Has replacement method
                        AccessController.doPrivileged(new PriviAction<Object>(
                                readResolve));
                        readResolveCache.put(objectClass, readResolve);
                        readResolveMethod = readResolve;
                    }
                }
                if (readResolveMethod != null) {
                    try {
                        result = ((Method) readResolveMethod).invoke(result,
                                (Object[]) null);
                    } catch (IllegalAccessException iae) {
                    } catch (InvocationTargetException ite) {
                        Throwable target = ite.getTargetException();
                        if (target instanceof ObjectStreamException) {
                            throw (ObjectStreamException) target;
                        } else if (target instanceof Error) {
                            throw (Error) target;
                        } else {
                            throw (RuntimeException) target;
                        }
                    }
                }
            }
        }
        // We get here either if class-based replacement was not needed or if it
        // was needed but produced the same object or if it could not be
        // computed.

        // The object to return is the one we instantiated or a replacement for
        // it
        if (result != null && enableResolve) {
            result = resolveObject(result);
        }
        if (registeredResult != result) {
            registerObjectRead(result, newHandle, unshared);
        }
        return result;
    
private java.lang.ClassreadNewProxyClassDesc()
Reads a new proxy class descriptor from the receiver. It is assumed the proxy class descriptor has not been read yet (not a cyclic reference). Return the proxy class descriptor read.

return
The {@code Class} read from the stream.
throws
IOException If an IO exception happened when reading the class descriptor.
throws
ClassNotFoundException If a class for one of the objects could not be found

        int count = input.readInt();
        String[] interfaceNames = new String[count];
        for (int i = 0; i < count; i++) {
            interfaceNames[i] = input.readUTF();
        }
        Class<?> proxy = resolveProxyClass(interfaceNames);
        // Consume unread class annotation data and TC_ENDBLOCKDATA
        discardData();
        return proxy;
    
private java.lang.ObjectreadNewString(boolean unshared)
Read a string encoded in {@link DataInput modified UTF-8} from the receiver. Return the string read.

param
unshared read the object unshared
return
the string just read.
throws
IOException If an IO exception happened when reading the String.

        Object result = input.readUTF();
        if (enableResolve) {
            result = resolveObject(result);
        }
        int newHandle = nextHandle();
        registerObjectRead(result, Integer.valueOf(newHandle), unshared);

        return result;
    
private java.lang.ObjectreadNonPrimitiveContent(boolean unshared)
Reads the content of the receiver based on the previously read token {@code tc}. Primitive data content is considered an error.

param
unshared read the object unshared
return
the object read from the stream
throws
IOException If an IO exception happened when reading the class descriptor.
throws
ClassNotFoundException If the class corresponding to the object being read could not be found.

        checkReadPrimitiveTypes();
        if (primitiveData.available() > 0) {
            OptionalDataException e = new OptionalDataException();
            e.length = primitiveData.available();
            throw e;
        }

        do {
            byte tc = nextTC();
            switch (tc) {
                case TC_CLASS:
                    return readNewClass(unshared);
                case TC_CLASSDESC:
                    return readNewClassDesc(unshared);
                case TC_ARRAY:
                    return readNewArray(unshared);
                case TC_OBJECT:
                    return readNewObject(unshared);
                case TC_STRING:
                    return readNewString(unshared);
                case TC_LONGSTRING:
                    return readNewLongString(unshared);
                case TC_ENUM:
                    return readEnum(unshared);
                case TC_REFERENCE:
                    if (unshared) {
                        readNewHandle();
                        throw new InvalidObjectException(Msg.getString("KA002")); //$NON-NLS-1$
                    }
                    return readCyclicReference();
                case TC_NULL:
                    return null;
                case TC_EXCEPTION:
                    Exception exc = readException();
                    throw new WriteAbortedException(Msg.getString("K00d3"), exc); //$NON-NLS-1$
                case TC_RESET:
                    resetState();
                    break;
                case TC_ENDBLOCKDATA: // Can occur reading class annotation
                    pushbackTC();
                    OptionalDataException e = new OptionalDataException();
                    e.eof = true;
                    throw e;
                default:
                    throw new StreamCorruptedException(Msg.getString(
                            "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
            }
            // Only TC_RESET falls through
        } while (true);
    
public final java.lang.ObjectreadObject()
Reads the next object from the source stream.

return
the object read from the source stream.
throws
ClassNotFoundException if the class of one of the objects in the object graph cannot be found.
throws
IOException if an error occurs while reading from the source stream.
throws
OptionalDataException if primitive data types were found instead of an object.
see
ObjectOutputStream#writeObject(Object)
since
Android 1.0

        return readObject(false);
    
private java.lang.ObjectreadObject(boolean unshared)

        boolean restoreInput = (primitiveData == input);
        if (restoreInput) {
            primitiveData = emptyStream;
        }

        // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
        // behavior overriding.
        if (subclassOverridingImplementation && !unshared) {
            return readObjectOverride();
        }

        // If we still had primitive types to read, should we discard them
        // (reset the primitiveTypes stream) or leave as is, so that attempts to
        // read primitive types won't read 'past data' ???
        Object result;
        try {
            // We need this so we can tell when we are returning to the
            // original/outside caller
            if (++nestedLevels == 1) {
                // Remember the caller's class loader
                // BEGIN android-changed
                callerClassLoader = getClosestUserClassLoader();
                // END android-changed
            }

            result = readNonPrimitiveContent(unshared);
            if (restoreInput) {
                primitiveData = input;
            }
        } finally {
            // We need this so we can tell when we are returning to the
            // original/outside caller
            if (--nestedLevels == 0) {
                // We are going to return to the original caller, perform
                // cleanups.
                // No more need to remember the caller's class loader
                callerClassLoader = null;
            }
        }

        // Done reading this object. Is it time to return to the original
        // caller? If so we need to perform validations first.
        if (nestedLevels == 0 && validations != null) {
            // We are going to return to the original caller. If validation is
            // enabled we need to run them now and then cleanup the validation
            // collection
            try {
                for (InputValidationDesc element : validations) {
                    element.validator.validateObject();
                }
            } finally {
                // Validations have to be renewed, since they are only called
                // from readObject
                validations = null;
            }
        }
        return result;
    
private voidreadObjectForClass(java.lang.Object object, java.io.ObjectStreamClass classDesc)

        // Have to do this before calling defaultReadObject or anything that
        // calls defaultReadObject
        currentObject = object;
        currentClass = classDesc;

        boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) > 0;
        Class<?> targetClass = classDesc.forClass();
        final Method readMethod;
        if (targetClass == null || !mustResolve) {
            readMethod = null;
        } else {
            readMethod = ObjectStreamClass
                    .getPrivateReadObjectMethod(targetClass);
        }
        try {
            if (readMethod != null) {
                // We have to be able to fetch its value, even if it is private
                AccessController.doPrivileged(new PriviAction<Object>(
                        readMethod));
                try {
                    readMethod.invoke(object, new Object[] { this });
                } catch (InvocationTargetException e) {
                    Throwable ex = e.getTargetException();
                    if (ex instanceof ClassNotFoundException) {
                        throw (ClassNotFoundException) ex;
                    } else if (ex instanceof RuntimeException) {
                        throw (RuntimeException) ex;
                    } else if (ex instanceof Error) {
                        throw (Error) ex;
                    }
                    throw (IOException) ex;
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e.toString());
                }
            } else {
                defaultReadObject();
            }
            if (hadWriteMethod) {
                discardData();
            }
        } finally {
            // Cleanup, needs to run always so that we can later detect invalid
            // calls to defaultReadObject
            currentObject = null; // We did not set this, so we do not need to
            // clean it
            currentClass = null;
        }
    
private voidreadObjectNoData(java.lang.Object object, java.lang.Class cl)

        if (!ObjectStreamClass.isSerializable(cl)) {
            return;
        }

        final Method readMethod = ObjectStreamClass
                .getPrivateReadObjectNoDataMethod(cl);
        if (readMethod != null) {
            AccessController.doPrivileged(new PriviAction<Object>(readMethod));
            try {
                readMethod.invoke(object, new Object[0]);
            } catch (InvocationTargetException e) {
                Throwable ex = e.getTargetException();
                if (ex instanceof RuntimeException) {
                    throw (RuntimeException) ex;
                } else if (ex instanceof Error) {
                    throw (Error) ex;
                }
                throw (ObjectStreamException) ex;
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e.toString());
            }
        }
    
protected java.lang.ObjectreadObjectOverride()
Method to be overriden by subclasses to read the next object from the source stream.

return
the object read from the source stream.
throws
ClassNotFoundException if the class of one of the objects in the object graph cannot be found.
throws
IOException if an error occurs while reading from the source stream.
throws
OptionalDataException if primitive data types were found instead of an object.
see
ObjectOutputStream#writeObjectOverride
since
Android 1.0

        if (input == null) {
            return null;
        }
        // Subclasses must override.
        throw new IOException();
    
public shortreadShort()
Reads a short (16 bit) from the source stream.

return
the short value read from the source stream.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readShort();
    
protected voidreadStreamHeader()
Reads and validates the ObjectInputStream header from the source stream.

throws
IOException if an error occurs while reading from the source stream.
throws
StreamCorruptedException if the source stream does not contain readable serialized objects.
since
Android 1.0

        if (input.readShort() == STREAM_MAGIC
                && input.readShort() == STREAM_VERSION) {
            return;
        }
        throw new StreamCorruptedException();
    
public java.lang.StringreadUTF()
Reads a string encoded in {@link DataInput modified UTF-8} from the source stream.

return
the string encoded in {@link DataInput modified UTF-8} read from the source stream.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readUTF();
    
public java.lang.ObjectreadUnshared()
Reads the next unshared object from the source stream.

return
the new object read.
throws
ClassNotFoundException if the class of one of the objects in the object graph cannot be found.
throws
IOException if an error occurs while reading from the source stream.
see
ObjectOutputStream#writeUnshared
since
Android 1.0

        return readObject(true);
    
public intreadUnsignedByte()
Reads an unsigned byte (8 bit) from the source stream.

return
the unsigned byte value read from the source stream packaged in an integer.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readUnsignedByte();
    
public intreadUnsignedShort()
Reads an unsigned short (16 bit) from the source stream.

return
the unsigned short value read from the source stream packaged in an integer.
throws
EOFException if the end of the input is reached before the read request can be satisfied.
throws
IOException if an error occurs while reading from the source stream.
since
Android 1.0

        return primitiveTypes.readUnsignedShort();
    
private voidregisterObjectRead(java.lang.Object obj, java.lang.Integer handle, boolean unshared)
Assume object {@code obj} has been read, and assign a handle to it, {@code handle}.

param
obj Non-null object being loaded.
param
handle An Integer, the handle to this object
param
unshared Boolean, indicates that caller is reading in unshared mode
see
#nextHandle

        objectsRead.put(handle, unshared ? UNSHARED_OBJ : obj);
    
public synchronized voidregisterValidation(java.io.ObjectInputValidation object, int priority)
Registers a callback for post-deserialization validation of objects. It allows to perform additional consistency checks before the {@code readObject()} method of this class returns its result to the caller. This method can only be called from within the {@code readObject()} method of a class that implements "special" deserialization rules. It can be called multiple times. Validation callbacks are then done in order of decreasing priority, defined by {@code priority}.

param
object an object that can validate itself by receiving a callback.
param
priority the validator's priority.
throws
InvalidObjectException if {@code object} is {@code null}.
throws
NotActiveException if this stream is currently not reading objects. In that case, calling this method is not allowed.
see
ObjectInputValidation#validateObject()

        // Validation can only be registered when inside readObject calls
        Object instanceBeingRead = this.currentObject;

        // We can't be called from just anywhere. There are rules.
        if (instanceBeingRead == null) {
            throw new NotActiveException();
        }
        if (object == null) {
            throw new InvalidObjectException(Msg.getString("K00d9")); //$NON-NLS-1$
        }
        // From now on it is just insertion in a SortedCollection. Since
        // the Java class libraries don't provide that, we have to
        // implement it from scratch here.
        InputValidationDesc desc = new InputValidationDesc();
        desc.validator = object;
        desc.priority = priority;
        // No need for this, validateObject does not take a parameter
        // desc.toValidate = instanceBeingRead;
        if (validations == null) {
            validations = new InputValidationDesc[1];
            validations[0] = desc;
        } else {
            int i = 0;
            for (; i < validations.length; i++) {
                InputValidationDesc validation = validations[i];
                // Sorted, higher priority first.
                if (priority >= validation.priority) {
                    break; // Found the index where to insert
                }
            }
            InputValidationDesc[] oldValidations = validations;
            int currentSize = oldValidations.length;
            validations = new InputValidationDesc[currentSize + 1];
            System.arraycopy(oldValidations, 0, validations, 0, i);
            System.arraycopy(oldValidations, i, validations, i + 1, currentSize
                    - i);
            validations[i] = desc;
        }
    
private java.lang.ObjectregisteredObjectRead(java.lang.Integer handle)
Return the object previously read tagged with handle {@code handle}.

param
handle The handle that this object was assigned when it was read.
return
the object previously read.
throws
InvalidObjectException If there is no previously read object with this handle

        Object res = objectsRead.get(handle);

        if (res == UNSHARED_OBJ) {
            throw new InvalidObjectException(Msg.getString("KA010")); //$NON-NLS-1$
        }

        return res;
    
private voidresetSeenObjects()
Reset the collection of objects already loaded by the receiver.

        objectsRead = new Hashtable<Integer, Object>();
        currentHandle = baseWireHandle;
        primitiveData = emptyStream;
    
private voidresetState()
Reset the receiver. The collection of objects already read by the receiver is reset, and internal structures are also reset so that the receiver knows it is in a fresh clean state.

        resetSeenObjects();
        hasPushbackTC = false;
        pushbackTC = 0;
        // nestedLevels = 0;
    
protected java.lang.ClassresolveClass(java.io.ObjectStreamClass osClass)
Loads the Java class corresponding to the class descriptor {@code osClass} that has just been read from the source stream.

param
osClass an ObjectStreamClass read from the source stream.
return
a Class corresponding to the descriptor {@code osClass}.
throws
ClassNotFoundException if the class for an object cannot be found.
throws
IOException if an I/O error occurs while creating the class.
see
ObjectOutputStream#annotateClass(Class)
since
Android 1.0

        String className = osClass.getName();
        // if it is primitive class, for example, long.class
        Class<?> cls = PRIMITIVE_CLASSES.get(className);
        if (null == cls) {
            // not primitive class
            // Use the first non-null ClassLoader on the stack. If null, use the
            // system class loader
            return Class.forName(className, true, callerClassLoader);
        }
        return cls;
    
protected java.lang.ObjectresolveObject(java.lang.Object object)
Allows trusted subclasses to substitute the specified original {@code object} with a new object. Object substitution has to be activated first with calling {@code enableResolveObject(true)}. This implementation just returns {@code object}.

param
object the original object for which a replacement may be defined.
return
the replacement object for {@code object}.
throws
IOException if any I/O error occurs while creating the replacement object.
see
#enableResolveObject
see
ObjectOutputStream#enableReplaceObject
see
ObjectOutputStream#replaceObject
since
Android 1.0

        // By default no object replacement. Subclasses can override
        return object;
    
protected java.lang.ClassresolveProxyClass(java.lang.String[] interfaceNames)
Creates the proxy class that implements the interfaces specified in {@code interfaceNames}.

param
interfaceNames the interfaces used to create the proxy class.
return
the proxy class.
throws
ClassNotFoundException if the proxy class or any of the specified interfaces cannot be created.
throws
IOException if an error occurs while reading from the source stream.
see
ObjectOutputStream#annotateProxyClass(Class)
since
Android 1.0

        // BEGIN android-removed
        // ClassLoader loader = VM.getNonBootstrapClassLoader();
        // END android-removed
        // BEGIN android-added
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        // END android-added
        Class<?>[] interfaces = new Class<?>[interfaceNames.length];
        for (int i = 0; i < interfaceNames.length; i++) {
            interfaces[i] = Class.forName(interfaceNames[i], false, loader);
        }
        try {
            return Proxy.getProxyClass(loader, interfaces);
        } catch (IllegalArgumentException e) {
            throw new ClassNotFoundException(e.toString(), e);
        }
    
private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, byte value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code byte} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, char value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code char} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, double value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code double} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, float value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code float} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, int value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code int} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, long value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code long} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, short value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code short} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

private static native voidsetField(java.lang.Object instance, java.lang.Class declaringClass, java.lang.String fieldName, boolean value)
Set a given declared field named {@code fieldName} of {@code instance} to the new {@code boolean} value {@code value}. This method could be implemented non-natively on top of java.lang.reflect implementations that support the {@code setAccessible} API, at the expense of extra object creation (java.lang.reflect.Field). Otherwise Serialization could not set private fields, except by the use of a native method like this one.

param
instance Object whose field to set
param
declaringClass {@code instance}'s declaring class
param
fieldName Name of the field to set
param
value New value for the field
throws
NoSuchFieldError If the field does not exist.

public intskipBytes(int length)
Skips {@code length} bytes on the source stream. This method should not be used to skip bytes at any arbitrary position, just when reading primitive data types (int, char etc).

param
length the number of bytes to skip.
return
the number of bytes actually skipped.
throws
IOException if an error occurs while skipping bytes on the source stream.
throws
NullPointerException if the source stream is {@code null}.
since
Android 1.0

        // To be used with available. Ok to call if reading primitive buffer
        if (input == null) {
            throw new NullPointerException();
        }

        int offset = 0;
        while (offset < length) {
            checkReadPrimitiveTypes();
            long skipped = primitiveData.skip(length - offset);
            if (skipped == 0) {
                return offset;
            }
            offset += (int) skipped;
        }
        return length;
    
private voidverifyBaseName(java.io.ObjectStreamClass loadedStreamClass)
Verify if the base name for descriptor {@code loadedStreamClass} matches the base name of the corresponding loaded class.

param
loadedStreamClass An ObjectStreamClass that was loaded from the stream.
throws
InvalidClassException If the base name of the stream class does not match the VM class

        Class<?> localClass = loadedStreamClass.forClass();
        ObjectStreamClass localStreamClass = ObjectStreamClass
                .lookupStreamClass(localClass);
        String loadedClassBaseName = getBaseName(loadedStreamClass.getName());
        String localClassBaseName = getBaseName(localStreamClass.getName());

        if (!loadedClassBaseName.equals(localClassBaseName)) {
            throw new InvalidClassException(loadedStreamClass.getName(), Msg
                    .getString("KA015", loadedClassBaseName, //$NON-NLS-1$
                            localClassBaseName));
        }
    
private voidverifySUID(java.io.ObjectStreamClass loadedStreamClass)
Verify if the SUID for descriptor {@code loadedStreamClass}matches the SUID of the corresponding loaded class.

param
loadedStreamClass An ObjectStreamClass that was loaded from the stream.
throws
InvalidClassException If the SUID of the stream class does not match the VM class

        Class<?> localClass = loadedStreamClass.forClass();
        // Instances of java.lang.Class are always Serializable, even if their
        // instances aren't (e.g. java.lang.Object.class). We cannot call lookup
        // because it returns null if the parameter represents instances that
        // cannot be serialized, and that is not what we want. If we are loading
        // an instance of java.lang.Class, we better have the corresponding
        // ObjectStreamClass.
        ObjectStreamClass localStreamClass = ObjectStreamClass
                .lookupStreamClass(localClass);
        if (loadedStreamClass.getSerialVersionUID() != localStreamClass
                .getSerialVersionUID()) {
            throw new InvalidClassException(loadedStreamClass.getName(), Msg
                    .getString("K00da", loadedStreamClass, //$NON-NLS-1$
                            localStreamClass));
        }