Index: java/io/ObjectInputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/io/ObjectInputStream.java,v retrieving revision 1.64 diff -u -3 -p -u -r1.64 ObjectInputStream.java --- java/io/ObjectInputStream.java 9 Sep 2005 12:12:03 -0000 1.64 +++ java/io/ObjectInputStream.java 12 Sep 2005 14:14:21 -0000 @@ -120,7 +120,8 @@ public class ObjectInputStream extends I * @exception IOException Exception from underlying * InputStream. */ - public final Object readObject() throws ClassNotFoundException, IOException + public final Object readObject() + throws ClassNotFoundException, IOException { if (this.useSubclassMethod) return readObjectOverride(); @@ -130,7 +131,6 @@ public class ObjectInputStream extends I Object ret_val; was_deserializing = this.isDeserializing; - boolean is_consumed = false; boolean old_mode = setBlockDataMode(false); this.isDeserializing = true; @@ -143,271 +143,285 @@ public class ObjectInputStream extends I try { - switch (marker) + ret_val = parseContent(marker); + } + finally + { + setBlockDataMode(old_mode); + + this.isDeserializing = was_deserializing; + + depth -= 2; + + if (! was_deserializing) { - case TC_ENDBLOCKDATA: + if (validators.size() > 0) + invokeValidators(); + } + } + + return ret_val; + } + + /** + * Handles a content block within the stream, which begins with a marker + * byte indicating its type. + * + * @param byte the byte marker. + * @return an object which represents the parsed content. + * @throws ClassNotFoundException if the class of an object being + * read in cannot be found. + * @throws IOException if invalid data occurs or one is thrown by the + * underlying InputStream. + */ + private Object parseContent(byte marker) + throws ClassNotFoundException, IOException + { + Object ret_val; + boolean is_consumed = false; + + switch (marker) + { + case TC_ENDBLOCKDATA: + { + ret_val = null; + is_consumed = true; + break; + } + + case TC_BLOCKDATA: + case TC_BLOCKDATALONG: + { + if (marker == TC_BLOCKDATALONG) + { if(dump) dumpElementln("BLOCKDATALONG"); } + else + { if(dump) dumpElementln("BLOCKDATA"); } + readNextBlock(marker); + throw new StreamCorruptedException("Unexpected blockData"); + } + + case TC_NULL: + { + if(dump) dumpElementln("NULL"); + ret_val = null; + break; + } + + case TC_REFERENCE: + { + if(dump) dumpElement("REFERENCE "); + Integer oid = new Integer(this.realInputStream.readInt()); + if(dump) dumpElementln(Integer.toHexString(oid.intValue())); + ret_val = ((ObjectIdentityWrapper) + this.objectLookupTable.get(oid)).object; + break; + } + + case TC_CLASS: + { + if(dump) dumpElementln("CLASS"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + assignNewHandle(clazz); + ret_val = clazz; + break; + } + + case TC_PROXYCLASSDESC: + { + if(dump) dumpElementln("PROXYCLASS"); + int n_intf = this.realInputStream.readInt(); + String[] intfs = new String[n_intf]; + for (int i = 0; i < n_intf; i++) + { + intfs[i] = this.realInputStream.readUTF(); + System.out.println(intfs[i]); + } + + boolean oldmode = setBlockDataMode(true); + Class cl = resolveProxyClass(intfs); + setBlockDataMode(oldmode); + + ObjectStreamClass osc = lookupClass(cl); + assignNewHandle(osc); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + ObjectStreamClass superosc = (ObjectStreamClass)readObject(); + osc.setSuperclass(superosc); + ret_val = osc; + break; + } + + case TC_CLASSDESC: + { + ObjectStreamClass osc = readClassDescriptor(); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + + osc.setSuperclass ((ObjectStreamClass)readObject()); + ret_val = osc; + break; + } + + case TC_STRING: + case TC_LONGSTRING: + { + if(dump) dumpElement("STRING="); + String s = this.realInputStream.readUTF(); + if(dump) dumpElementln(s); + ret_val = processResolution(null, s, assignNewHandle(s)); + break; + } + + case TC_ARRAY: + { + if(dump) dumpElementln("ARRAY"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class componentType = osc.forClass().getComponentType(); + if(dump) dumpElement("ARRAY LENGTH="); + int length = this.realInputStream.readInt(); + if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); + Object array = Array.newInstance(componentType, length); + int handle = assignNewHandle(array); + readArrayElements(array, componentType); + if(dump) + for (int i = 0, len = Array.getLength(array); i < len; i++) + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + ret_val = processResolution(null, array, handle); + break; + } + + case TC_OBJECT: + { + if(dump) dumpElementln("OBJECT"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + + if (!osc.realClassIsSerializable) + throw new NotSerializableException + (clazz + " is not Serializable, and thus cannot be deserialized."); + + if (osc.realClassIsExternalizable) { - ret_val = null; - is_consumed = true; - break; - } - - case TC_BLOCKDATA: - case TC_BLOCKDATALONG: - { - if (marker == TC_BLOCKDATALONG) - { if(dump) dumpElementln("BLOCKDATALONG"); } - else - { if(dump) dumpElementln("BLOCKDATA"); } - readNextBlock(marker); - throw new StreamCorruptedException("Unexpected blockData"); - } - - case TC_NULL: - { - if(dump) dumpElementln("NULL"); - ret_val = null; - break; - } - - case TC_REFERENCE: - { - if(dump) dumpElement("REFERENCE "); - Integer oid = new Integer(this.realInputStream.readInt()); - if(dump) dumpElementln(Integer.toHexString(oid.intValue())); - ret_val = ((ObjectIdentityWrapper) - this.objectLookupTable.get(oid)).object; - break; - } - - case TC_CLASS: - { - if(dump) dumpElementln("CLASS"); - ObjectStreamClass osc = (ObjectStreamClass)readObject(); - Class clazz = osc.forClass(); - assignNewHandle(clazz); - ret_val = clazz; - break; - } - - case TC_PROXYCLASSDESC: - { - if(dump) dumpElementln("PROXYCLASS"); - int n_intf = this.realInputStream.readInt(); - String[] intfs = new String[n_intf]; - for (int i = 0; i < n_intf; i++) - { - intfs[i] = this.realInputStream.readUTF(); - } + Externalizable obj = osc.newInstance(); - boolean oldmode = setBlockDataMode(true); - Class cl = resolveProxyClass(intfs); - setBlockDataMode(oldmode); + int handle = assignNewHandle(obj); - ObjectStreamClass osc = lookupClass(cl); - assignNewHandle(osc); + boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); - if (!is_consumed) - { - byte b = this.realInputStream.readByte(); - if (b != TC_ENDBLOCKDATA) - throw new IOException("Data annotated to class was not consumed." + b); - } - else - is_consumed = false; - ObjectStreamClass superosc = (ObjectStreamClass)readObject(); - osc.setSuperclass(superosc); - osc.firstNonSerializableParentConstructor = - superosc.firstNonSerializableParentConstructor; - osc.fieldMapping = new ObjectStreamField[0]; - osc.realClassIsSerializable = true; - ret_val = osc; - break; - } - - case TC_CLASSDESC: - { - ObjectStreamClass osc = readClassDescriptor(); + boolean oldmode = this.readDataFromBlock; + if (read_from_blocks) + setBlockDataMode(true); - if (!is_consumed) - { - byte b = this.realInputStream.readByte(); - if (b != TC_ENDBLOCKDATA) - throw new IOException("Data annotated to class was not consumed." + b); + obj.readExternal(this); + + if (read_from_blocks) + { + setBlockDataMode(oldmode); + if (!oldmode) + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); } - else - is_consumed = false; - - osc.setSuperclass ((ObjectStreamClass)readObject()); - ret_val = osc; - break; - } - case TC_STRING: - case TC_LONGSTRING: - { - if(dump) dumpElement("STRING="); - String s = this.realInputStream.readUTF(); - if(dump) dumpElementln(s); - ret_val = processResolution(null, s, assignNewHandle(s)); - break; - } - - case TC_ARRAY: - { - if(dump) dumpElementln("ARRAY"); - ObjectStreamClass osc = (ObjectStreamClass)readObject(); - Class componentType = osc.forClass().getComponentType(); - if(dump) dumpElement("ARRAY LENGTH="); - int length = this.realInputStream.readInt(); - if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); - Object array = Array.newInstance(componentType, length); - int handle = assignNewHandle(array); - readArrayElements(array, componentType); - if(dump) - for (int i = 0, len = Array.getLength(array); i < len; i++) - dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); - ret_val = processResolution(null, array, handle); - break; - } - - case TC_OBJECT: - { - if(dump) dumpElementln("OBJECT"); - ObjectStreamClass osc = (ObjectStreamClass)readObject(); - Class clazz = osc.forClass(); - - if (!osc.realClassIsSerializable) - throw new NotSerializableException - (clazz + " is not Serializable, and thus cannot be deserialized."); + ret_val = processResolution(osc, obj, handle); + break; - if (osc.realClassIsExternalizable) - { - Externalizable obj = osc.newInstance(); - - int handle = assignNewHandle(obj); - - boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); - - boolean oldmode = this.readDataFromBlock; - if (read_from_blocks) - setBlockDataMode(true); - - obj.readExternal(this); - - if (read_from_blocks) - { - setBlockDataMode(oldmode); - if (!oldmode) - if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) - throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); - } - - ret_val = processResolution(osc, obj, handle); - break; - } // end if (osc.realClassIsExternalizable) - - Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); - - int handle = assignNewHandle(obj); - Object prevObject = this.currentObject; - ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; - - this.currentObject = obj; - ObjectStreamClass[] hierarchy = - inputGetObjectStreamClasses(clazz); - - for (int i = 0; i < hierarchy.length; i++) - { - this.currentObjectStreamClass = hierarchy[i]; - - if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); - - // XXX: should initialize fields in classes in the hierarchy - // that aren't in the stream - // should skip over classes in the stream that aren't in the - // real classes hierarchy - - Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; - if (readObjectMethod != null) - { - fieldsAlreadyRead = false; - boolean oldmode = setBlockDataMode(true); - callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); - setBlockDataMode(oldmode); - } - else - { - readFields(obj, currentObjectStreamClass); - } - - if (this.currentObjectStreamClass.hasWriteMethod()) - { - if(dump) dumpElement("ENDBLOCKDATA? "); - try - { - // FIXME: XXX: This try block is to - // catch EOF which is thrown for some - // objects. That indicates a bug in - // the logic. - - if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) - throw new IOException - ("No end of block data seen for class with readObject (ObjectInputStream) method."); - if(dump) dumpElementln("yes"); - } -// catch (EOFException e) -// { -// if(dump) dumpElementln("no, got EOFException"); -// } - catch (IOException e) - { - if(dump) dumpElementln("no, got IOException"); + } // end if (osc.realClassIsExternalizable) + + Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); + + int handle = assignNewHandle(obj); + Object prevObject = this.currentObject; + ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; + + this.currentObject = obj; + ObjectStreamClass[] hierarchy = + inputGetObjectStreamClasses(clazz); + + for (int i = 0; i < hierarchy.length; i++) + { + this.currentObjectStreamClass = hierarchy[i]; + if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); + + // XXX: should initialize fields in classes in the hierarchy + // that aren't in the stream + // should skip over classes in the stream that aren't in the + // real classes hierarchy + + Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; + if (readObjectMethod != null) + { + fieldsAlreadyRead = false; + boolean oldmode = setBlockDataMode(true); + callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); + setBlockDataMode(oldmode); + } + else + { + readFields(obj, currentObjectStreamClass); + } + + if (this.currentObjectStreamClass.hasWriteMethod()) + { + if(dump) dumpElement("ENDBLOCKDATA? "); + try + { + /* Read blocks until an end marker */ + byte writeMarker = this.realInputStream.readByte(); + while (writeMarker != TC_ENDBLOCKDATA) + { + parseContent(writeMarker); + writeMarker = this.realInputStream.readByte(); } + if(dump) dumpElementln("yes"); + } + catch (EOFException e) + { + throw (IOException) new IOException + ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e); } } - - this.currentObject = prevObject; - this.currentObjectStreamClass = prevObjectStreamClass; - ret_val = processResolution(osc, obj, handle); - - break; } - - case TC_RESET: - if(dump) dumpElementln("RESET"); - clearHandles(); - ret_val = readObject(); - break; - - case TC_EXCEPTION: - { - if(dump) dumpElement("EXCEPTION="); - Exception e = (Exception)readObject(); - if(dump) dumpElementln(e.toString()); - clearHandles(); - throw new WriteAbortedException("Exception thrown during writing of stream", e); - } - - default: - throw new IOException("Unknown marker on stream: " + marker); - } - } - finally - { - setBlockDataMode(old_mode); + + this.currentObject = prevObject; + this.currentObjectStreamClass = prevObjectStreamClass; + ret_val = processResolution(osc, obj, handle); + + break; + } - this.isDeserializing = was_deserializing; + case TC_RESET: + if(dump) dumpElementln("RESET"); + clearHandles(); + ret_val = readObject(); + break; - depth -= 2; + case TC_EXCEPTION: + { + if(dump) dumpElement("EXCEPTION="); + Exception e = (Exception)readObject(); + if(dump) dumpElementln(e.toString()); + clearHandles(); + throw new WriteAbortedException("Exception thrown during writing of stream", e); + } - if (! was_deserializing) - { - if (validators.size() > 0) - invokeValidators(); - } + default: + throw new IOException("Unknown marker on stream: " + marker); } - return ret_val; }