diff options
Diffstat (limited to 'libjava/java/io')
-rw-r--r-- | libjava/java/io/ObjectInputStream.java | 822 | ||||
-rw-r--r-- | libjava/java/io/ObjectOutputStream.java | 502 | ||||
-rw-r--r-- | libjava/java/io/ObjectStreamField.java | 23 | ||||
-rw-r--r-- | libjava/java/io/natObjectInputStream.cc | 13 | ||||
-rw-r--r-- | libjava/java/io/natObjectOutputStream.cc | 33 |
5 files changed, 750 insertions, 643 deletions
diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index 08ce401fad8..f2b2df8ed58 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* ObjectInputStream.java -- Class used to read serialized objects - Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,8 +38,6 @@ exception statement from your version. */ package java.io; -import gnu.classpath.Configuration; - import java.lang.reflect.Array; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; @@ -53,7 +51,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; - +import gnu.classpath.Configuration; public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants @@ -130,286 +128,343 @@ public class ObjectInputStream extends InputStream Object ret_val; was_deserializing = this.isDeserializing; - if (! was_deserializing) - setBlockDataMode (false); + boolean is_consumed = false; + boolean old_mode = setBlockDataMode (false); this.isDeserializing = true; byte marker = this.realInputStream.readByte (); dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " "); - switch (marker) - { - case TC_BLOCKDATA: - case TC_BLOCKDATALONG: - if (marker == TC_BLOCKDATALONG) - dumpElementln ("BLOCKDATALONG"); - else - dumpElementln ("BLOCKDATA"); - readNextBlock (marker); - throw new StreamCorruptedException ("Unexpected blockData"); - - case TC_NULL: - dumpElementln ("NULL"); - ret_val = null; - break; - - case TC_REFERENCE: - { - dumpElement ("REFERENCE "); - Integer oid = new Integer (this.realInputStream.readInt ()); - dumpElementln (Integer.toHexString(oid.intValue())); - ret_val = ((ObjectIdentityWrapper) - this.objectLookupTable.get (oid)).object; - break; - } - - case TC_CLASS: - { - dumpElementln ("CLASS"); - ObjectStreamClass osc = (ObjectStreamClass)readObject (); - Class clazz = osc.forClass (); - assignNewHandle (clazz); - ret_val = clazz; - break; - } - - case TC_CLASSDESC: - { - dumpElement ("CLASSDESC NAME="); - String name = this.realInputStream.readUTF (); - dumpElement (name + "; UID="); - long uid = this.realInputStream.readLong (); - dumpElement (Long.toHexString(uid) + "; FLAGS="); - byte flags = this.realInputStream.readByte (); - dumpElement (Integer.toHexString(flags) + "; FIELD COUNT="); - short field_count = this.realInputStream.readShort (); - dumpElementln (Short.toString(field_count)); - ObjectStreamField[] fields = new ObjectStreamField[field_count]; - - ObjectStreamClass osc = new ObjectStreamClass (name, uid, - flags, fields); - assignNewHandle (osc); - - for (int i=0; i < field_count; i++) - { - dumpElement (" TYPE CODE="); - char type_code = (char)this.realInputStream.readByte (); - dumpElement (type_code + "; FIELD NAME="); - String field_name = this.realInputStream.readUTF (); - dumpElementln (field_name); - String class_name; - - if (type_code == 'L' || type_code == '[') - class_name = (String)readObject (); - else - class_name = String.valueOf (type_code); - - fields[i] = - new ObjectStreamField (field_name, - TypeSignature.getClassForEncoding - (class_name)); - } - - Class cl = resolveClass (osc); - osc.setClass (cl); - setBlockDataMode (false); - - if (this.realInputStream.readByte () != TC_ENDBLOCKDATA) - throw new IOException ("Data annotated to class was not consumed."); - dumpElementln ("ENDBLOCKDATA "); - - osc.setSuperclass ((ObjectStreamClass)readObject ()); - ret_val = osc; - break; - } - - case TC_STRING: - { - dumpElement ("STRING="); - String s = this.realInputStream.readUTF (); - dumpElementln (s); - ret_val = processResolution (s, assignNewHandle (s)); - break; - } - - case TC_ARRAY: - { - dumpElementln ("ARRAY"); - ObjectStreamClass osc = (ObjectStreamClass)readObject (); - Class componentType = osc.forClass ().getComponentType (); - dumpElement ("ARRAY LENGTH="); - int length = this.realInputStream.readInt (); - dumpElementln (length + "; COMPONENT TYPE=" + componentType); - Object array = Array.newInstance (componentType, length); - int handle = assignNewHandle (array); - readArrayElements (array, componentType); - for (int i=0, len=Array.getLength(array); i < len; i++) - dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i)); - ret_val = processResolution (array, handle); - break; - } - - case TC_OBJECT: + try { - dumpElementln ("OBJECT"); - ObjectStreamClass osc = (ObjectStreamClass)readObject (); - Class clazz = osc.forClass (); - - if (!Serializable.class.isAssignableFrom (clazz)) - throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized."); - - if (Externalizable.class.isAssignableFrom (clazz)) - { - Externalizable obj = null; - - try - { - obj = (Externalizable)clazz.newInstance (); - } - catch (InstantiationException e) - { - throw new ClassNotFoundException ("Instance of " + clazz - + " could not be created"); - } - catch (IllegalAccessException e) - { - throw new ClassNotFoundException ("Instance of " + clazz - + " could not be created because class or zero-argument constructor is not accessible"); - } - catch (NoSuchMethodError e) + switch (marker) { - throw new ClassNotFoundException ("Instance of " + clazz - + " could not be created because zero-argument constructor is not defined"); - } - - int handle = assignNewHandle (obj); - - boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0); - - if (read_from_blocks) - setBlockDataMode (true); - - obj.readExternal (this); - - if (read_from_blocks) - setBlockDataMode (false); - - ret_val = processResolution (obj, handle); - break; - } // end if (Externalizable.class.isAssignableFrom (clazz)) + case TC_ENDBLOCKDATA: + { + ret_val = null; + is_consumed = true; + break; + } + + case TC_BLOCKDATA: + case TC_BLOCKDATALONG: + { + if (marker == TC_BLOCKDATALONG) + dumpElementln ("BLOCKDATALONG"); + else + dumpElementln ("BLOCKDATA"); + readNextBlock (marker); + throw new StreamCorruptedException ("Unexpected blockData"); + } + + case TC_NULL: + { + dumpElementln ("NULL"); + ret_val = null; + break; + } + + case TC_REFERENCE: + { + dumpElement ("REFERENCE "); + Integer oid = new Integer (this.realInputStream.readInt ()); + dumpElementln (Integer.toHexString(oid.intValue())); + ret_val = ((ObjectIdentityWrapper) + this.objectLookupTable.get (oid)).object; + break; + } + + case TC_CLASS: + { + dumpElementln ("CLASS"); + ObjectStreamClass osc = (ObjectStreamClass)readObject (); + Class clazz = osc.forClass (); + assignNewHandle (clazz); + ret_val = clazz; + break; + } + + case TC_PROXYCLASSDESC: + { + 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 = ObjectStreamClass.lookup(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: + { + dumpElement ("CLASSDESC NAME="); + String name = this.realInputStream.readUTF (); + dumpElement (name + "; UID="); + long uid = this.realInputStream.readLong (); + dumpElement (Long.toHexString(uid) + "; FLAGS="); + byte flags = this.realInputStream.readByte (); + dumpElement (Integer.toHexString(flags) + "; FIELD COUNT="); + short field_count = this.realInputStream.readShort (); + dumpElementln (Short.toString(field_count)); + ObjectStreamField[] fields = new ObjectStreamField[field_count]; + + ObjectStreamClass osc = new ObjectStreamClass (name, uid, + flags, fields); + assignNewHandle (osc); + + for (int i=0; i < field_count; i++) + { + dumpElement (" TYPE CODE="); + char type_code = (char)this.realInputStream.readByte (); + dumpElement (type_code + "; FIELD NAME="); + String field_name = this.realInputStream.readUTF (); + dumpElementln (field_name); + String class_name; + + if (type_code == 'L' || type_code == '[') + class_name = (String)readObject (); + else + class_name = String.valueOf (type_code); + + // There're many cases you can't get java.lang.Class from + // typename if your context class loader can't load it, + // then use typename to construct the field + fields[i] = + new ObjectStreamField (field_name, class_name); + } + + boolean oldmode = setBlockDataMode (true); + osc.setClass (resolveClass (osc)); + setBlockDataMode (oldmode); + + 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: + { + dumpElement ("STRING="); + String s = this.realInputStream.readUTF (); + dumpElementln (s); + ret_val = processResolution (s, assignNewHandle (s)); + break; + } + + case TC_ARRAY: + { + dumpElementln ("ARRAY"); + ObjectStreamClass osc = (ObjectStreamClass)readObject (); + Class componentType = osc.forClass ().getComponentType (); + dumpElement ("ARRAY LENGTH="); + int length = this.realInputStream.readInt (); + dumpElementln (length + "; COMPONENT TYPE=" + componentType); + Object array = Array.newInstance (componentType, length); + int handle = assignNewHandle (array); + readArrayElements (array, componentType); + for (int i=0, len=Array.getLength(array); i < len; i++) + dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i)); + ret_val = processResolution (array, handle); + break; + } + + case TC_OBJECT: + { + dumpElementln ("OBJECT"); + ObjectStreamClass osc = (ObjectStreamClass)readObject (); + Class clazz = osc.forClass (); + + if (!Serializable.class.isAssignableFrom (clazz)) + throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized."); + + if (Externalizable.class.isAssignableFrom (clazz)) + { + Externalizable obj = null; + + try + { + obj = (Externalizable)clazz.newInstance (); + } + catch (InstantiationException e) + { + throw new ClassNotFoundException ("Instance of " + clazz + + " could not be created"); + } + catch (IllegalAccessException e) + { + throw new ClassNotFoundException ("Instance of " + clazz + + " could not be created because class or zero-argument constructor is not accessible"); + } + catch (NoSuchMethodError e) + { + throw new ClassNotFoundException ("Instance of " + clazz + + " could not be created because zero-argument constructor is not defined"); + } + + 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); + + ret_val = processResolution (obj, handle); + break; + } // end if (Externalizable.class.isAssignableFrom (clazz)) + + // find the first non-serializable, non-abstract + // class in clazz's inheritance hierarchy + Class first_nonserial = clazz.getSuperclass (); + while (Serializable.class.isAssignableFrom (first_nonserial) + || Modifier.isAbstract (first_nonserial.getModifiers ())) + first_nonserial = first_nonserial.getSuperclass (); + + // DEBUGln ("Using " + first_nonserial + // + " as starting point for constructing " + clazz); + + Object obj = null; + obj = newObject (clazz, first_nonserial); + + if (obj == null) + throw new ClassNotFoundException ("Instance of " + clazz + + " could not be created"); + + int handle = assignNewHandle (obj); + this.currentObject = obj; + ObjectStreamClass[] hierarchy = + ObjectStreamClass.getObjectStreamClasses (clazz); + + // DEBUGln ("Got class hierarchy of depth " + hierarchy.length); + + boolean has_read; + for (int i=0; i < hierarchy.length; i++) + { + this.currentObjectStreamClass = hierarchy[i]; + + dumpElementln ("Reading fields of " + + this.currentObjectStreamClass.getName ()); + + has_read = true; + + try + { + this.currentObjectStreamClass.forClass (). + getDeclaredMethod ("readObject", readObjectParams); + } + catch (NoSuchMethodException e) + { + has_read = false; + } + + // 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 + readFields (obj, this.currentObjectStreamClass.fields, + has_read, this.currentObjectStreamClass); + + if (has_read) + { + 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."); + dumpElementln ("yes"); + } + catch (EOFException e) + { + dumpElementln ("no, got EOFException"); + } + catch (IOException e) + { + dumpElementln ("no, got IOException"); + } + } + } + + this.currentObject = null; + this.currentObjectStreamClass = null; + ret_val = processResolution (obj, handle); + break; + } + + case TC_RESET: + dumpElementln ("RESET"); + clearHandles (); + ret_val = readObject (); + break; + + case TC_EXCEPTION: + { + dumpElement ("EXCEPTION="); + Exception e = (Exception)readObject (); + dumpElementln (e.toString()); + clearHandles (); + throw new WriteAbortedException ("Exception thrown during writing of stream", e); + } + + default: + throw new IOException ("Unknown marker on stream: " + marker); - // find the first non-serializable, non-abstract - // class in clazz's inheritance hierarchy - Class first_nonserial = clazz.getSuperclass (); - while (Serializable.class.isAssignableFrom (first_nonserial) - || Modifier.isAbstract (first_nonserial.getModifiers ())) - first_nonserial = first_nonserial.getSuperclass (); - -// DEBUGln ("Using " + first_nonserial -// + " as starting point for constructing " + clazz); - - Object obj = null; - obj = newObject (clazz, first_nonserial); - - if (obj == null) - throw new ClassNotFoundException ("Instance of " + clazz + - " could not be created"); - - int handle = assignNewHandle (obj); - this.currentObject = obj; - ObjectStreamClass[] hierarchy = - ObjectStreamClass.getObjectStreamClasses (clazz); - -// DEBUGln ("Got class hierarchy of depth " + hierarchy.length); - - boolean has_read; - for (int i=0; i < hierarchy.length; i++) - { - this.currentObjectStreamClass = hierarchy[i]; - - dumpElementln ("Reading fields of " - + this.currentObjectStreamClass.getName ()); - - has_read = true; - - try - { - this.currentObjectStreamClass.forClass (). - getDeclaredMethod ("readObject", readObjectParams); } - catch (NoSuchMethodException e) - { - has_read = false; - } - - // 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 - readFields (obj, this.currentObjectStreamClass.fields, - has_read, this.currentObjectStreamClass); - - if (has_read) - { - 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."); - dumpElementln ("yes"); - } - catch (EOFException e) - { - dumpElementln ("no, got EOFException"); - } - catch (IOException e) - { - dumpElementln ("no, got IOException"); - } - } - } - - this.currentObject = null; - this.currentObjectStreamClass = null; - ret_val = processResolution (obj, handle); - break; } - - case TC_RESET: - dumpElementln ("RESET"); - clearHandles (); - ret_val = readObject (); - break; - - case TC_EXCEPTION: + finally { - dumpElement ("EXCEPTION="); - Exception e = (Exception)readObject (); - dumpElementln (e.toString()); - clearHandles (); - throw new WriteAbortedException ("Exception thrown during writing of stream", e); + setBlockDataMode (old_mode); + + this.isDeserializing = was_deserializing; + + if (! was_deserializing) + { + if (validators.size () > 0) + invokeValidators (); + } } - - default: - throw new IOException ("Unknown marker on stream"); - } - - this.isDeserializing = was_deserializing; - - if (! was_deserializing) - { - setBlockDataMode (true); - - if (validators.size () > 0) - invokeValidators (); - } - + return ret_val; } - + /** Reads the current objects non-transient, non-static fields from @@ -439,9 +494,11 @@ public class ObjectInputStream extends InputStream if (fieldsAlreadyRead) throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)"); + boolean oldmode = setBlockDataMode(false); readFields (this.currentObject, this.currentObjectStreamClass.fields, false, this.currentObjectStreamClass); + setBlockDataMode(oldmode); fieldsAlreadyRead = true; } @@ -500,13 +557,18 @@ public class ObjectInputStream extends InputStream throws ClassNotFoundException, IOException { SecurityManager sm = System.getSecurityManager (); + if (sm == null) + sm = new SecurityManager () {}; // FIXME: currentClassLoader doesn't yet do anything useful. We need // to call forName() with the classloader of the class which called // readObject(). See SecurityManager.getClassContext(). ClassLoader cl = currentClassLoader (sm); - return Class.forName (osc.getName (), true, cl); + if (cl == null) + return Class.forName (osc.getName ()); + else + return cl.loadClass (osc.getName ()); } /** @@ -617,7 +679,17 @@ public class ObjectInputStream extends InputStream if (this.readDataFromBlock) { if (this.blockDataPosition + length > this.blockDataBytes) - readNextBlock (); + { + int remain = this.blockDataBytes - this.blockDataPosition; + if (remain != 0) + { + System.arraycopy (this.blockData, this.blockDataPosition, + data, offset, remain); + offset += remain; + length -= remain; + } + readNextBlock (); + } System.arraycopy (this.blockData, this.blockDataPosition, data, offset, length); @@ -785,11 +857,11 @@ public class ObjectInputStream extends InputStream // Apparently Block data is not used with GetField as per // empirical evidence against JDK 1.2. Also see Mauve test // java.io.ObjectInputOutput.Test.GetPutField. - setBlockDataMode (false); + boolean oldmode = setBlockDataMode (false); readFully (prim_field_data); for (int i = 0; i < objs.length; ++ i) objs[i] = readObject (); - setBlockDataMode (true); + setBlockDataMode (oldmode); return new GetField () { @@ -990,7 +1062,7 @@ public class ObjectInputStream extends InputStream de serialization mechanism provided by <code>ObjectInputStream</code>. To make this method be used for writing objects, subclasses must invoke the 0-argument - constructor on this class from there constructor. + constructor on this class from their constructor. @see ObjectInputStream () */ @@ -1175,9 +1247,9 @@ public class ObjectInputStream extends InputStream { // DEBUGln (" call_read_method is true"); fieldsAlreadyRead = false; - setBlockDataMode (true); + boolean oldmode = setBlockDataMode (true); callReadMethod (obj, stream_osc.forClass ()); - setBlockDataMode (false); + setBlockDataMode (oldmode); return; } @@ -1237,101 +1309,109 @@ public class ObjectInputStream extends InputStream } } - if (type == Boolean.TYPE) - { - boolean value = - default_initialize ? false : this.realInputStream.readBoolean (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setBooleanField (obj, field_name, value); - } - else if (type == Byte.TYPE) - { - byte value = - default_initialize ? 0 : this.realInputStream.readByte (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setByteField (obj, field_name, value); - } - else if (type == Character.TYPE) - { - char value = - default_initialize ? (char)0 : this.realInputStream.readChar (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setCharField (obj, field_name, value); - } - else if (type == Double.TYPE) - { - double value = - default_initialize ? 0 : this.realInputStream.readDouble (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setDoubleField (obj, field_name, value); - } - else if (type == Float.TYPE) - { - float value = - default_initialize ? 0 : this.realInputStream.readFloat (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setFloatField (obj, field_name, value); - } - else if (type == Integer.TYPE) - { - int value = - default_initialize ? 0 : this.realInputStream.readInt (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setIntField (obj, field_name, value); - } - else if (type == Long.TYPE) - { - long value = - default_initialize ? 0 : this.realInputStream.readLong (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setLongField (obj, field_name, value); - } - else if (type == Short.TYPE) - { - short value = - default_initialize ? (short)0 : this.realInputStream.readShort (); - if (!default_initialize && set_value) - dumpElementln (" " + field_name + ": " + value); - if (set_value) - setShortField (obj, field_name, value); - } - else - { - Object value = - default_initialize ? null : readObject (); - if (set_value) - setObjectField (obj, field_name, - real_field.getTypeString (), value); - } + try + { + if (type == Boolean.TYPE) + { + boolean value = + default_initialize ? false : this.realInputStream.readBoolean (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setBooleanField (obj, field_name, value); + } + else if (type == Byte.TYPE) + { + byte value = + default_initialize ? 0 : this.realInputStream.readByte (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setByteField (obj, field_name, value); + } + else if (type == Character.TYPE) + { + char value = + default_initialize ? (char)0 : this.realInputStream.readChar (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setCharField (obj, field_name, value); + } + else if (type == Double.TYPE) + { + double value = + default_initialize ? 0 : this.realInputStream.readDouble (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setDoubleField (obj, field_name, value); + } + else if (type == Float.TYPE) + { + float value = + default_initialize ? 0 : this.realInputStream.readFloat (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setFloatField (obj, field_name, value); + } + else if (type == Integer.TYPE) + { + int value = + default_initialize ? 0 : this.realInputStream.readInt (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setIntField (obj, field_name, value); + } + else if (type == Long.TYPE) + { + long value = + default_initialize ? 0 : this.realInputStream.readLong (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setLongField (obj, field_name, value); + } + else if (type == Short.TYPE) + { + short value = + default_initialize ? (short)0 : this.realInputStream.readShort (); + if (!default_initialize && set_value) + dumpElementln (" " + field_name + ": " + value); + if (set_value) + setShortField (obj, field_name, value); + } + else + { + Object value = + default_initialize ? null : readObject (); + if (set_value) + setObjectField (obj, field_name, + real_field.getTypeString (), value); + } + } + catch (NoSuchFieldError e) + { + dumpElementln("XXXX " + field_name + " does not exist."); + } } } // Toggles writing primitive data to block-data buffer. - private void setBlockDataMode (boolean on) + private boolean setBlockDataMode (boolean on) { // DEBUGln ("Setting block data mode to " + on); - + boolean oldmode = this.readDataFromBlock; this.readDataFromBlock = on; if (on) this.dataInputStream = this.blockDataInput; else this.dataInputStream = this.realInputStream; + return oldmode; } @@ -1380,12 +1460,18 @@ public class ObjectInputStream extends InputStream return ClassLoader.getSystemClassLoader (); } - private static native Field getField (Class klass, String name) - throws java.lang.NoSuchFieldException; - - private static native Method getMethod (Class klass, String name, Class args[]) - throws java.lang.NoSuchMethodException; - + private static Field getField (Class klass, String name) + throws java.lang.NoSuchFieldException + { + return klass.getDeclaredField(name); + } + + private static Method getMethod (Class klass, String name, Class args[]) + throws java.lang.NoSuchMethodException + { + return klass.getDeclaredMethod(name, args); + } + private void callReadMethod (Object obj, Class klass) throws IOException { try @@ -1593,6 +1679,14 @@ public class ObjectInputStream extends InputStream if (Configuration.DEBUG && dump) System.out.println(msg); } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javaio"); + } + } } diff --git a/libjava/java/io/ObjectOutputStream.java b/libjava/java/io/ObjectOutputStream.java index d7c893f1696..d522996d7a5 100644 --- a/libjava/java/io/ObjectOutputStream.java +++ b/libjava/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* ObjectOutputStream.java -- Class used to write serialized objects - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,6 +46,7 @@ import java.util.Hashtable; import gnu.java.io.ObjectIdentityWrapper; import gnu.java.lang.reflect.TypeSignature; +import gnu.classpath.Configuration; /** An <code>ObjectOutputStream</code> can be used to write objects @@ -167,229 +168,242 @@ public class ObjectOutputStream extends OutputStream public final void writeObject (Object obj) throws IOException { if (useSubclassMethod) - { - writeObjectOverride (obj); - return; - } + { + writeObjectOverride (obj); + return; + } boolean was_serializing = isSerializing; - - if (! was_serializing) - setBlockDataMode (false); - + boolean old_mode = setBlockDataMode (false); try - { - isSerializing = true; - boolean replaceDone = false; - - drain (); - - while (true) { - if (obj == null) - { - realOutput.writeByte (TC_NULL); - break; - } - - Integer handle = findHandle (obj); - if (handle != null) - { - realOutput.writeByte (TC_REFERENCE); - realOutput.writeInt (handle.intValue ()); - break; - } - - if (obj instanceof Class) - { - realOutput.writeByte (TC_CLASS); - writeObject (ObjectStreamClass.lookup ((Class)obj)); - assignNewHandle (obj); - break; - } - - if (obj instanceof ObjectStreamClass) - { - ObjectStreamClass osc = (ObjectStreamClass)obj; - realOutput.writeByte (TC_CLASSDESC); - realOutput.writeUTF (osc.getName ()); - realOutput.writeLong (osc.getSerialVersionUID ()); - assignNewHandle (obj); - - int flags = osc.getFlags (); - - if (protocolVersion == PROTOCOL_VERSION_2 - && osc.isExternalizable ()) - flags |= SC_BLOCK_DATA; - - realOutput.writeByte (flags); - - ObjectStreamField[] fields = osc.fields; - realOutput.writeShort (fields.length); - - ObjectStreamField field; - for (int i=0; i < fields.length; i++) - { - field = fields[i]; - realOutput.writeByte (field.getTypeCode ()); - realOutput.writeUTF (field.getName ()); - - if (! field.isPrimitive ()) - writeObject (field.getTypeString ()); - } - - setBlockDataMode (true); - annotateClass (osc.forClass ()); - setBlockDataMode (false); - realOutput.writeByte (TC_ENDBLOCKDATA); - - if (osc.isSerializable ()) - writeObject (osc.getSuper ()); - else - writeObject (null); - break; - } - - + isSerializing = true; + boolean replaceDone = false; Object replacedObject = null; - - if ((replacementEnabled || obj instanceof Serializable) - && ! replaceDone) - { - replacedObject = obj; - - if (obj instanceof Serializable) - { - Method m = null; - try + + while (true) + { + if (obj == null) + { + realOutput.writeByte (TC_NULL); + break; + } + + Integer handle = findHandle (obj); + if (handle != null) + { + realOutput.writeByte (TC_REFERENCE); + realOutput.writeInt (handle.intValue ()); + break; + } + + if (obj instanceof Class) + { + Class cl = (Class)obj; + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl); + assignNewHandle (obj); + realOutput.writeByte (TC_CLASS); + if (!osc.isProxyClass) + { + writeObject(osc); + } + else + { + realOutput.writeByte (TC_PROXYCLASSDESC); + Class[] intfs = cl.getInterfaces(); + realOutput.writeInt(intfs.length); + for (int i = 0; i < intfs.length; i++) + realOutput.writeUTF(intfs[i].getName()); + + boolean oldmode = setBlockDataMode (true); + annotateProxyClass(cl); + setBlockDataMode (oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + + writeObject (osc.getSuper()); + } + break; + } + + if (obj instanceof ObjectStreamClass) + { + ObjectStreamClass osc = (ObjectStreamClass)obj; + realOutput.writeByte (TC_CLASSDESC); + realOutput.writeUTF (osc.getName ()); + realOutput.writeLong (osc.getSerialVersionUID ()); + assignNewHandle (obj); + + int flags = osc.getFlags (); + + if (protocolVersion == PROTOCOL_VERSION_2 + && osc.isExternalizable ()) + flags |= SC_BLOCK_DATA; + + realOutput.writeByte (flags); + + ObjectStreamField[] fields = osc.fields; + realOutput.writeShort (fields.length); + + ObjectStreamField field; + for (int i=0; i < fields.length; i++) + { + field = fields[i]; + realOutput.writeByte (field.getTypeCode ()); + realOutput.writeUTF (field.getName ()); + + if (! field.isPrimitive ()) + writeObject (field.getTypeString ()); + } + + boolean oldmode = setBlockDataMode (true); + annotateClass (osc.forClass ()); + setBlockDataMode (oldmode); + realOutput.writeByte (TC_ENDBLOCKDATA); + + if (osc.isSerializable ()) + writeObject (osc.getSuper ()); + else + writeObject (null); + break; + } + + if ((replacementEnabled || obj instanceof Serializable) + && ! replaceDone) { - Class classArgs[] = {}; - m = obj.getClass ().getDeclaredMethod ("writeReplace", - classArgs); - // m can't be null by definition since an exception would - // have been thrown so a check for null is not needed. - obj = m.invoke (obj, new Object[] {}); + replacedObject = obj; + + if (obj instanceof Serializable) + { + Method m = null; + try + { + Class classArgs[] = {}; + m = obj.getClass ().getDeclaredMethod ("writeReplace", + classArgs); + // m can't be null by definition since an exception would + // have been thrown so a check for null is not needed. + obj = m.invoke (obj, new Object[] {}); + } + catch (NoSuchMethodException ignore) + { + } + catch (IllegalAccessException ignore) + { + } + catch (InvocationTargetException ignore) + { + } + } + + if (replacementEnabled) + obj = replaceObject (obj); + + replaceDone = true; + continue; } - catch (NoSuchMethodException ignore) + + if (obj instanceof String) { + realOutput.writeByte (TC_STRING); + assignNewHandle (obj); + realOutput.writeUTF ((String)obj); + break; } - catch (IllegalAccessException ignore) + + Class clazz = obj.getClass (); + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject (clazz); + if (osc == null) + throw new NotSerializableException (clazz.getName ()); + + if (clazz.isArray ()) { + realOutput.writeByte (TC_ARRAY); + writeObject (osc); + assignNewHandle (obj); + writeArraySizeAndElements (obj, clazz.getComponentType ()); + break; } - catch (InvocationTargetException ignore) + + realOutput.writeByte (TC_OBJECT); + writeObject (osc); + + if (replaceDone) + assignNewHandle (replacedObject); + else + assignNewHandle (obj); + + if (obj instanceof Externalizable) { + if (protocolVersion == PROTOCOL_VERSION_2) + setBlockDataMode (true); + + ((Externalizable)obj).writeExternal (this); + + if (protocolVersion == PROTOCOL_VERSION_2) + { + setBlockDataMode (false); + realOutput.writeByte (TC_ENDBLOCKDATA); + } + + break; } - } - - if (replacementEnabled) - obj = replaceObject (obj); - - replaceDone = true; - continue; - } - - if (obj instanceof String) - { - realOutput.writeByte (TC_STRING); - assignNewHandle (obj); - realOutput.writeUTF ((String)obj); - break; - } - - Class clazz = obj.getClass (); - ObjectStreamClass osc = ObjectStreamClass.lookup (clazz); - if (osc == null) - throw new NotSerializableException (clazz.getName ()); - - if (clazz.isArray ()) - { - realOutput.writeByte (TC_ARRAY); - writeObject (osc); - assignNewHandle (obj); - writeArraySizeAndElements (obj, clazz.getComponentType ()); - break; - } - - realOutput.writeByte (TC_OBJECT); - writeObject (osc); - - if (replaceDone) - assignNewHandle (replacedObject); - else - assignNewHandle (obj); - - if (obj instanceof Externalizable) - { - if (protocolVersion == PROTOCOL_VERSION_2) - setBlockDataMode (true); - - ((Externalizable)obj).writeExternal (this); - - if (protocolVersion == PROTOCOL_VERSION_2) + + if (obj instanceof Serializable) + { + currentObject = obj; + ObjectStreamClass[] hierarchy = + ObjectStreamClass.getObjectStreamClasses (clazz); + + boolean has_write; + for (int i=0; i < hierarchy.length; i++) + { + currentObjectStreamClass = hierarchy[i]; + + fieldsAlreadyWritten = false; + has_write = currentObjectStreamClass.hasWriteMethod (); + + writeFields (obj, currentObjectStreamClass.fields, + has_write); + + } + + currentObject = null; + currentObjectStreamClass = null; + currentPutField = null; + break; + } + + throw new NotSerializableException (clazz.getName ()); + } // end pseudo-loop + } + catch (ObjectStreamException ose) + { + // Rethrow these are fatal. + throw ose; + } + catch (IOException e) + { + realOutput.writeByte (TC_EXCEPTION); + reset (true); + + setBlockDataMode (false); + try { - setBlockDataMode (false); - drain (); + writeObject (e); } - - break; - } - - if (obj instanceof Serializable) - { - currentObject = obj; - ObjectStreamClass[] hierarchy = - ObjectStreamClass.getObjectStreamClasses (clazz); - - boolean has_write; - for (int i=0; i < hierarchy.length; i++) + catch (IOException ioe) { - currentObjectStreamClass = hierarchy[i]; - - fieldsAlreadyWritten = false; - has_write = currentObjectStreamClass.hasWriteMethod (); - - writeFields (obj, currentObjectStreamClass.fields, - has_write); - - if (has_write) - { - drain (); - realOutput.writeByte (TC_ENDBLOCKDATA); - } + throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream."); } - - currentObject = null; - currentObjectStreamClass = null; - currentPutField = null; - break; - } - - throw new NotSerializableException (clazz.getName ()); - } // end pseudo-loop - } - catch (IOException e) - { - realOutput.writeByte (TC_EXCEPTION); - reset (true); - - try - { - writeObject (e); + + reset (true); } - catch (IOException ioe) - { - throw new StreamCorruptedException ("Exception " + ioe + " thrown while exception was being written to stream."); - } - - reset (true); - } finally - { - isSerializing = was_serializing; + { + isSerializing = was_serializing; - if (! was_serializing) - setBlockDataMode (true); - } + setBlockDataMode (old_mode); + } } @@ -466,8 +480,8 @@ public class ObjectOutputStream extends OutputStream according to the specified protocol. There are currently two different protocols, specified by <code>PROTOCOL_VERSION_1</code> and <code>PROTOCOL_VERSION_2</code>. This implementation writes - data using <code>PROTOCOL_VERSION_1</code> by default, as is done - by the JDK 1.1. + data using <code>PROTOCOL_VERSION_2</code> by default, as is done + by the JDK 1.2. A non-portable method, <code>setDefaultProtocolVersion (int version)</code> is provided to change the default protocol @@ -528,6 +542,8 @@ public class ObjectOutputStream extends OutputStream protected void annotateClass (Class cl) throws IOException {} + protected void annotateProxyClass(Class cl) throws IOException + {} /** Allows subclasses to replace objects that are written to the @@ -702,7 +718,8 @@ public class ObjectOutputStream extends OutputStream if (blockDataCount == 0) return; - writeBlockDataHeader (blockDataCount); + if (writeDataAsBlocks) + writeBlockDataHeader (blockDataCount); realOutput.write (blockData, 0, blockDataCount); blockDataCount = 0; } @@ -713,7 +730,7 @@ public class ObjectOutputStream extends OutputStream */ public void close () throws IOException { - drain (); + flush (); realOutput.close (); } @@ -723,7 +740,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeBoolean (boolean data) throws IOException { - dataOutput.writeBoolean (data); + blockDataOutput.writeBoolean (data); } @@ -732,7 +749,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeByte (int data) throws IOException { - dataOutput.writeByte (data); + blockDataOutput.writeByte (data); } @@ -741,7 +758,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeShort (int data) throws IOException { - dataOutput.writeShort (data); + blockDataOutput.writeShort (data); } @@ -750,7 +767,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeChar (int data) throws IOException { - dataOutput.writeChar (data); + blockDataOutput.writeChar (data); } @@ -759,7 +776,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeInt (int data) throws IOException { - dataOutput.writeInt (data); + blockDataOutput.writeInt (data); } @@ -768,7 +785,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeLong (long data) throws IOException { - dataOutput.writeLong (data); + blockDataOutput.writeLong (data); } @@ -777,7 +794,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeFloat (float data) throws IOException { - dataOutput.writeFloat (data); + blockDataOutput.writeFloat (data); } @@ -786,7 +803,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeDouble (double data) throws IOException { - dataOutput.writeDouble (data); + blockDataOutput.writeDouble (data); } @@ -795,7 +812,7 @@ public class ObjectOutputStream extends OutputStream */ public void writeBytes (String data) throws IOException { - dataOutput.writeBytes (data); + blockDataOutput.writeBytes (data); } @@ -965,6 +982,8 @@ public class ObjectOutputStream extends OutputStream { ObjectStreamField field = currentObjectStreamClass.getField (name); + if (field == null) + throw new IllegalArgumentException (); if (value != null && ! field.getType ().isAssignableFrom (value.getClass ())) throw new IllegalArgumentException (); @@ -976,11 +995,11 @@ public class ObjectOutputStream extends OutputStream // Apparently Block data is not used with PutField as per // empirical evidence against JDK 1.2. Also see Mauve test // java.io.ObjectInputOutput.Test.GetPutField. - setBlockDataMode (false); + boolean oldmode = setBlockDataMode (false); out.write (prim_field_data); for (int i = 0; i < objs.length; ++ i) out.writeObject (objs[i]); - setBlockDataMode (true); + setBlockDataMode (oldmode); } private void checkType (ObjectStreamField field, char type) @@ -1067,8 +1086,7 @@ public class ObjectOutputStream extends OutputStream { byte[] cast_array = (byte[])array; realOutput.writeInt (length); - for (int i=0; i < length; i++) - realOutput.writeByte (cast_array[i]); + realOutput.write(cast_array, 0, length); return; } if (clazz == Character.TYPE) @@ -1142,9 +1160,11 @@ public class ObjectOutputStream extends OutputStream setBlockDataMode (true); callWriteMethod (obj); setBlockDataMode (false); + realOutput.writeByte (TC_ENDBLOCKDATA); return; } + boolean oldmode = setBlockDataMode (false); String field_name; Class type; for (int i=0; i < fields.length; i++) @@ -1170,20 +1190,28 @@ public class ObjectOutputStream extends OutputStream realOutput.writeShort (getShortField (obj, field_name)); else writeObject (getObjectField (obj, field_name, - TypeSignature.getEncodingOfClass (type))); + fields[i].getTypeString ())); } + setBlockDataMode(oldmode); } // Toggles writing primitive data to block-data buffer. - private void setBlockDataMode (boolean on) + private boolean setBlockDataMode (boolean on) throws IOException { + if (on == writeDataAsBlocks) + return on; + + drain(); + boolean oldmode = writeDataAsBlocks; writeDataAsBlocks = on; if (on) dataOutput = blockDataOutput; else dataOutput = realOutput; + + return oldmode; } @@ -1355,16 +1383,22 @@ public class ObjectOutputStream extends OutputStream } } - private static native Field getField (Class klass, String name) - throws java.lang.NoSuchFieldException; - - private static native Method getMethod (Class klass, String name, Class[] args) - throws java.lang.NoSuchMethodException; - + private static Field getField (Class klass, String name) + throws java.lang.NoSuchFieldException + { + return klass.getDeclaredField(name); + } + + private static Method getMethod (Class klass, String name, Class[] args) + throws java.lang.NoSuchMethodException + { + return klass.getDeclaredMethod(name, args); + } + // this value comes from 1.2 spec, but is used in 1.1 as well private final static int BUFFER_SIZE = 1024; - private static int defaultProtocolVersion = PROTOCOL_VERSION_1; + private static int defaultProtocolVersion = PROTOCOL_VERSION_2; private DataOutputStream dataOutput; private boolean writeDataAsBlocks; @@ -1382,4 +1416,12 @@ public class ObjectOutputStream extends OutputStream private Hashtable OIDLookupTable; private int protocolVersion; private boolean useSubclassMethod; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javaio"); + } + } } diff --git a/libjava/java/io/ObjectStreamField.java b/libjava/java/io/ObjectStreamField.java index e0f8d6131a8..bb78a786c1f 100644 --- a/libjava/java/io/ObjectStreamField.java +++ b/libjava/java/io/ObjectStreamField.java @@ -47,8 +47,23 @@ public class ObjectStreamField implements java.lang.Comparable { this.name = name; this.type = type; + this.typename = TypeSignature.getEncodingOfClass(type); } - + + /** + * There're many cases you can't get java.lang.Class from typename if your context + * class loader can't load it, then use typename to construct the field + */ + ObjectStreamField (String name, String typename){ + this.name = name; + this.typename = typename; + try{ + type = TypeSignature.getClassForEncoding(typename); + }catch(ClassNotFoundException e){ + type = Object.class; //?? + } + } + public String getName () { return name; @@ -61,12 +76,13 @@ public class ObjectStreamField implements java.lang.Comparable public char getTypeCode () { - return TypeSignature.getEncodingOfClass (type).charAt (0); + return typename.charAt (0); } public String getTypeString () { - return TypeSignature.getEncodingOfClass (type); + // use intern() + return typename.intern(); } public int getOffset () @@ -106,5 +122,6 @@ public class ObjectStreamField implements java.lang.Comparable private String name; private Class type; + private String typename; private int offset = -1; // XXX make sure this is correct } diff --git a/libjava/java/io/natObjectInputStream.cc b/libjava/java/io/natObjectInputStream.cc index 8240144827f..8b84e7e3199 100644 --- a/libjava/java/io/natObjectInputStream.cc +++ b/libjava/java/io/natObjectInputStream.cc @@ -69,16 +69,3 @@ java::io::ObjectInputStream::callConstructor (jclass klass, jobject obj) + m->offset); _Jv_CallAnyMethodA (obj, JvPrimClass (void), meth, false, arg_types, NULL); } - -java::lang::reflect::Field * -java::io::ObjectInputStream::getField (jclass klass, jstring name) -{ - return klass->getPrivateField (name); -} - -java::lang::reflect::Method * -java::io::ObjectInputStream::getMethod (jclass klass, jstring name, - JArray<jclass> *arg_types) -{ - return klass->getPrivateMethod (name, arg_types); -} diff --git a/libjava/java/io/natObjectOutputStream.cc b/libjava/java/io/natObjectOutputStream.cc deleted file mode 100644 index 45ab7537fc3..00000000000 --- a/libjava/java/io/natObjectOutputStream.cc +++ /dev/null @@ -1,33 +0,0 @@ -// natObjectOutputStream.cc - Native part of ObjectOutputStream class. - -/* Copyright (C) 1998, 1999 Free Software Foundation - - This ObjectOutputStream is part of libgcj. - -This software is copyrighted work licensed under the terms of the -Libgcj License. Please consult the ObjectOutputStream "LIBGCJ_LICENSE" for -details. */ - -#include <config.h> - -#include <gcj/cni.h> -#include <jvm.h> -#include <java/io/ObjectOutputStream$PutField.h> -#include <java/io/ObjectOutputStream.h> -#include <java/io/IOException.h> -#include <java/lang/Class.h> - - -java::lang::reflect::Field * -java::io::ObjectOutputStream::getField (jclass klass, jstring name) -{ - return klass->getPrivateField (name); -} - -java::lang::reflect::Method * -java::io::ObjectOutputStream::getMethod (jclass klass, jstring name, - JArray<jclass> *arg_types) -{ - return klass->getPrivateMethod (name, arg_types); -} - |