Index: java/io/ObjectInputStream.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/ObjectInputStream.java,v
retrieving revision 1.36
diff -u -r1.36 ObjectInputStream.java
--- java/io/ObjectInputStream.java	9 Jan 2004 08:59:30 -0000	1.36
+++ java/io/ObjectInputStream.java	30 Jan 2004 15:01:33 -0000
@@ -245,7 +245,7 @@
 	      dumpElement("STRING=");
 	      String s = this.realInputStream.readUTF();
 	      dumpElementln(s);
-	      ret_val = processResolution(s, assignNewHandle(s));
+	      ret_val = processResolution(null, s, assignNewHandle(s));
 	      break;
 	    }
 
@@ -262,7 +262,7 @@
 	      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);
+	      ret_val = processResolution(null, array, handle);
 	      break;
 	    }
 
@@ -315,7 +315,7 @@
 		  if (read_from_blocks)
 		    setBlockDataMode(oldmode);
 		  
-		  ret_val = processResolution(obj, handle);
+		  ret_val = processResolution(osc, obj, handle);
 		  break;
 		} // end if (Externalizable.class.isAssignableFrom (clazz))
 	      
@@ -349,11 +349,12 @@
 		  // should skip over classes in the stream that aren't in the
 		  // real classes hierarchy
 		  
-		  if (this.currentObjectStreamClass.hasReadMethod())
+		  Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
+		  if (readObjectMethod != null)
 		    {
 		      fieldsAlreadyRead = false;
 		      boolean oldmode = setBlockDataMode(true);
-		      callReadMethod(obj, this.currentObjectStreamClass);
+		      callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
 		      setBlockDataMode(oldmode);
 		      dumpElement("ENDBLOCKDATA? ");
 		      try
@@ -382,7 +383,7 @@
 
 	      this.currentObject = null;
 	      this.currentObjectStreamClass = null;
-	      ret_val = processResolution(obj, handle);
+	      ret_val = processResolution(osc, obj, handle);
 	      break;
 	    }
 
@@ -453,6 +454,8 @@
     ObjectStreamClass osc = new ObjectStreamClass(name, uid,
 						  flags, fields);
     assignNewHandle(osc);
+
+    ClassLoader currentLoader = currentLoader();
 	      
     for (int i = 0; i < field_count; i++)
       {
@@ -473,28 +476,29 @@
 	  class_name = String.valueOf(type_code);
 		  
 	fields[i] =
-	  new ObjectStreamField(field_name, class_name, currentLoader());
+	  new ObjectStreamField(field_name, class_name, currentLoader);
       }
 	      
     /* Now that fields have been read we may resolve the class
      * (and read annotation if needed). */
     Class clazz = resolveClass(osc);
     
+    Hashtable fieldLookup = new Hashtable();
+    ObjectStreamField[] real_fields = ObjectStreamClass.lookup(clazz).fields;
+    for (int i = 0; i < real_fields.length; i++)
+      {
+	fieldLookup.put(real_fields[i].getName(), real_fields[i]);
+      }
     for (int i = 0; i < field_count; i++)
       {
-	Field f;
-	
-	try
+	ObjectStreamField f = 
+	    (ObjectStreamField)fieldLookup.get(fields[i].getName());
+	if (f.getType() != fields[i].getType())
 	  {
-	    f = clazz.getDeclaredField(fields[i].getName());
-	    if (f != null && !f.getType().equals(fields[i].getType()))
-	      throw new InvalidClassException
+	    throw new InvalidClassException
 		("invalid field type for " + fields[i].getName() + " in class "
-		 + name + " (requested was \"" + fields[i].getType()
-		 + " and found \"" + f.getType() + "\")"); 
-	  }
-	catch (NoSuchFieldException _)
-	  {
+		+ name); 
 	  }
       }
 
@@ -1045,7 +1049,7 @@
    * deserializing class (if present). It cannot (and should not)be called
    * outside of it. Its goal is to read all fields in the real input stream
    * and keep them accessible through the {@link #GetField} class. Calling
-   * this method will not alterate the deserializing object.
+   * this method will not alter the deserializing object.
    *
    * @return A valid freshly created 'GetField' instance to get access to
    * the deserialized stream.
@@ -1375,20 +1379,18 @@
     return this.nextOID++;
   }
 
-  private Object processResolution(Object obj, int handle)
+  private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
     throws IOException
   {
-    if (obj instanceof Serializable)
+    if (osc != null && obj instanceof Serializable)
       {
-        Method m = null; 
 	try
 	  {
-	    Class classArgs[] = {};
-	    m = getMethod(obj.getClass(), "readResolve", classArgs);
-	    obj = m.invoke(obj, new Object[] {});	
-	  }
-	catch (NoSuchMethodException ignore)
-	  {
+	    Method m = osc.readResolveMethod; 
+	    if(m != null)
+	    {
+		obj = m.invoke(obj, new Object[] {});
+	    }
 	  }
 	catch (IllegalAccessException ignore)
 	  {
@@ -1519,156 +1521,163 @@
   {
     ObjectStreamField[] stream_fields = stream_osc.fields;
     ObjectStreamField[] real_fields =
-      lookupClass(stream_osc.forClass()).fields;
+      ObjectStreamClass.lookup(stream_osc.forClass()).fields;
 
-    boolean default_initialize, set_value;
-    String field_name = null;
-    Class type = null;
-    ObjectStreamField stream_field = null;
-    ObjectStreamField real_field = null;
     int stream_idx = 0;
     int real_idx = 0;
 
     while (stream_idx < stream_fields.length
-	   && real_idx < real_fields.length)
+	   || real_idx < real_fields.length)
       {
-	default_initialize = false;
-	set_value = true;
+	boolean read_value;
+	boolean set_value;
+	String field_name;
+	char type;
+	ObjectStreamField real_field;
 
 	if (stream_idx == stream_fields.length)
-	  default_initialize = true;
-	else
 	  {
-	    stream_field = stream_fields[stream_idx];
-	    type = stream_field.getType();
+	    real_field = real_fields[real_idx++];
+	    type = real_field.getTypeCode();
+	    field_name = real_field.getName();
+	    read_value = false;
+	    set_value = real_field.isToSet();
 	  }
-
-	if (real_idx == real_fields.length)
-	  set_value = false;
-	else
+	else if (real_idx == real_fields.length)
 	  {
-	    real_field = real_fields[real_idx];
-	    type = real_field.getType();
-	    field_name = real_field.getName();
+	    ObjectStreamField stream_field = stream_fields[stream_idx++];
+	    type = stream_field.getTypeCode();
+	    real_field = null;
+	    field_name = stream_field.getName();
+	    read_value = stream_field.getOffset() >= 0;
+	    set_value = false;
 	  }
-
-	if (set_value && !default_initialize)
+	else
 	  {
 	    int comp_val =
-	      real_field.compareTo (stream_field);
+		real_fields[real_idx].compareTo (stream_fields[stream_idx]);
 
 	    if (comp_val < 0)
 	      {
-		default_initialize = true;
-		real_idx++;
+		real_field = real_fields[real_idx++];
+		type = real_field.getTypeCode();
+		field_name = real_field.getName();
+		read_value = false;
+		set_value = real_field.isToSet();
 	      }
 	    else if (comp_val > 0)
 	      {
+		ObjectStreamField stream_field = stream_fields[stream_idx++];
+		real_field = null;
+		type = stream_field.getTypeCode();
+		field_name = stream_field.getName();
+		read_value = stream_field.getOffset() >= 0;
 		set_value = false;
-		stream_idx++;
 	      }
 	    else
 	      {
-		real_idx++;
-		stream_idx++;
+		ObjectStreamField stream_field = stream_fields[stream_idx++];
+		real_field = real_fields[real_idx++];
+		type = real_field.getTypeCode();
+		field_name = real_field.getName();
+		read_value = stream_field.getOffset() >= 0;
+		set_value = stream_field.isToSet() && real_field.isToSet();
 	      }
 	  }
 
-	if (stream_field.getOffset() < 0)
+	switch(type)
 	  {
-	    default_initialize = true;
-	    set_value = false;
-	  }
-	
-	if (!stream_field.isToSet()) 
-	  set_value = false;
-
-	try
-	  {
-	    if (type == Boolean.TYPE)
+	    case 'Z':
 	      {
 		boolean value =
-		  default_initialize ? false : this.realInputStream.readBoolean();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readBoolean() : false;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setBooleanField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setBooleanField(obj, value);
+		break;
 	      }
-	    else if (type == Byte.TYPE)
+	    case 'B':
 	      {
 		byte value =
-		  default_initialize ? 0 : this.realInputStream.readByte();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readByte() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setByteField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setByteField(obj, value);
+		break;
 	      }
-	    else if (type == Character.TYPE)
+	    case 'C':
 	      {
 		char value =
-		  default_initialize ? (char)0 : this.realInputStream.readChar();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readChar(): 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setCharField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setCharField(obj, value);
+		break;
 	      }
-	    else if (type == Double.TYPE)
+	    case 'D':
 	      {
 		double value =
-		  default_initialize ? 0 : this.realInputStream.readDouble();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readDouble() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setDoubleField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setDoubleField(obj, value);
+		break;
 	      }
-	    else if (type == Float.TYPE)
+	    case 'F':
 	      {
 		float value =
-		  default_initialize ? 0 : this.realInputStream.readFloat();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readFloat() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setFloatField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setFloatField(obj, value);
+		break;
 	      }
-	    else if (type == Integer.TYPE)
+	    case 'I':
 	      {
 		int value =
-		  default_initialize ? 0 : this.realInputStream.readInt();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readInt() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setIntField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setIntField(obj, value);
+		break;
 	      }
-	    else if (type == Long.TYPE)
+	    case 'J':
 	      {
 		long value =
-		  default_initialize ? 0 : this.realInputStream.readLong();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readLong() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setLongField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setLongField(obj, value);
+		break;
 	      }
-	    else if (type == Short.TYPE)
+	    case 'S':
 	      {
 		short value =
-		  default_initialize ? (short)0 : this.realInputStream.readShort();
-		if (!default_initialize && set_value)
+		  read_value ? this.realInputStream.readShort() : 0;
+		if (read_value && set_value)
 		  dumpElementln("  " + field_name + ": " + value);
 		if (set_value)
-		  setShortField(obj, stream_osc.forClass(), field_name, value);
+		  real_field.setShortField(obj, value);
+		break;
 	      }
-	    else
+	    case 'L':
+	    case '[':
 	      {
 		Object value =
-		  default_initialize ? null : readObject();
+		  read_value ? readObject() : null;
 		if (set_value)
-		  setObjectField(obj, stream_osc.forClass(), field_name,
-				  real_field.getTypeString(), value);
+		  real_field.setObjectField(obj, value);
+		break;
 	      }
-	  }
-	catch (NoSuchFieldError e)
-	  {
-	    dumpElementln("XXXX " + field_name + " does not exist.");
+	    default:
+		throw new InternalError("Invalid type code: " + type);
 	  }
       }
   }
@@ -1730,71 +1739,11 @@
    */
   private static native ClassLoader currentClassLoader (SecurityManager sm);
 
-  /**
-   * This method tries to access a precise field called in the
-   * specified class. Before accessing the field, it tries to
-   * gain control on this field. If the field is either declared as 
-   * not persistent or transient then it returns null
-   * immediately.
-   *
-   * @param klass Class to get the field from.
-   * @param name Name of the field to access.
-   * @return Field instance representing the requested field.
-   * @throws NoSuchFieldException if the field does not exist.
-   */
-  private Field getField(Class klass, String name)
-    throws java.lang.NoSuchFieldException
-  {
-    final Field f = klass.getDeclaredField(name);
-    ObjectStreamField sf = lookupClass(klass).getField(name);
-    
-    AccessController.doPrivileged(new PrivilegedAction()
-      {
-	public Object run()
-	{
-	  f.setAccessible(true);
-	  return null;
-	}
-      });
-
-    /* We do not want to modify transient fields. They should
-     * be left to 0.
-     * N.B.: Not valid if the field is in serialPersistentFields. 
-     */
-    if (Modifier.isTransient(f.getModifiers()) && !sf.isPersistent())
-      return null;
-   
-    return f;
-  }
-
-  private static Method getMethod (Class klass, String name, Class args[])
-    throws java.lang.NoSuchMethodException
-  {
-    final Method m = klass.getDeclaredMethod(name, args);
-    AccessController.doPrivileged(new PrivilegedAction()
-      {
-	public Object run()
-	{
-	  m.setAccessible(true);
-	  return null;
-	}
-      });
-    return m;
-  }
-
-  private void callReadMethod (Object obj, ObjectStreamClass osc) throws IOException
+  private void callReadMethod (Method readObject, Class klass, Object obj) throws IOException
   {
-    Class klass = osc.forClass();
     try
       {
-	Class classArgs[] = {ObjectInputStream.class};
-	Method m = getMethod (klass, "readObject", classArgs);
-	Object args[] = {this};
-	m.invoke(obj, args);
-      }
-    catch (NoSuchMethodException nsme)
-      {
-	// Nothing.
+	readObject.invoke(obj, new Object[] { this });
       }
     catch (InvocationTargetException x)
       {
@@ -1823,265 +1772,7 @@
 
   private native void callConstructor (Class clazz, Object obj);
 
-  /**
-   * This method writes a "boolean" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The boolean value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setBooleanField(Object obj, Class klass, String field_name,
-				boolean val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setBoolean(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes a "byte" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The byte value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setByteField(Object obj, Class klass, String field_name,
-			     byte val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setByte(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes a "character" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The character value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setCharField(Object obj, Class klass, String field_name,
-			     char val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setChar(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes a "double" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The double value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setDoubleField(Object obj, Class klass, String field_name,
-			       double val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setDouble(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes a "float" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The float value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setFloatField(Object obj, Class klass, String field_name,
-			      float val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setFloat(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes an "integer" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The integer value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setIntField(Object obj, Class klass, String field_name,
-			    int val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setInt(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes the long value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The long value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setLongField(Object obj, Class klass, String field_name,
-			     long val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setLong(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes a "short" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The short value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setShortField(Object obj, Class klass, String field_name,
-			      short val) throws IOException, InvalidClassException
-  {
-    try
-      {
-	Field f = getField(klass, field_name);
-	f.setShort(obj, val);
-      }
-    catch (IllegalArgumentException _)
-      {
-	throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
-      }
-    catch (Exception _)
-      {
-      }    
-  }
-
-  /**
-   * This method writes an "object" value <code>val</code> in the specified field
-   * of the instance <code>obj</code> of the type <code>klass</code>.
-   *
-   * @param obj Instance to setup.
-   * @param klass Class type of the specified instance.
-   * @param field_name Name of the field in the specified class type.
-   * @param val The "object" value to write into the field.
-   * @throws InvalidClassException if the specified field has not the required type.
-   * @throws IOException if there is no field of that name in the specified class.
-   */
-  private void setObjectField(Object obj, Class klass, String field_name,
-			       String type_code, Object val) throws IOException, InvalidClassException
-  {
-    try
-      {
- 	Field f = getField(klass, field_name);
-	ObjectStreamField of = new ObjectStreamField(field_name, f.getType());
-	
-	if (of.getTypeString() == null ||
-	    !of.getTypeString().equals(type_code))
-          throw new InvalidClassException("incompatible field type for " + klass.getName() + "." + field_name);
- 	f.set(obj, val);
-      }
-    catch (InvalidClassException e)
-      {
-	throw e;
-      }
-    catch (Exception _)
-      {
-      }
-  }
-
   private static final int BUFFER_SIZE = 1024;
-  private static final Class[] readObjectParams = { ObjectInputStream.class };
 
   private DataInputStream realInputStream;
   private DataInputStream dataInputStream;
Index: java/io/ObjectStreamClass.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/ObjectStreamClass.java,v
retrieving revision 1.29
diff -u -r1.29 ObjectStreamClass.java
--- java/io/ObjectStreamClass.java	30 Dec 2003 15:57:05 -0000	1.29
+++ java/io/ObjectStreamClass.java	30 Jan 2004 15:01:33 -0000
@@ -45,9 +45,11 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.security.AccessController;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
 import java.security.Security;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -192,29 +194,6 @@
     return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
   }
 
-
-  // Returns true iff the class that this ObjectStreamClass represents
-  // has the following method:
-  //
-  // private void readObject (ObjectOutputStream)
-  //
-  // This method is used by the class to override default
-  // serialization behavior.
-  boolean hasReadMethod()
-  {
-    try
-      {
-	Class[] readObjectParams = { ObjectInputStream.class };
-	forClass().getDeclaredMethod("readObject", readObjectParams);
-	return true;
-      }
-    catch (NoSuchMethodException e)
-      {
-	return false;
-      }
-  }
-
-
   // Returns true iff the class that this ObjectStreamClass represents
   // implements Serializable but does *not* implement Externalizable.
   boolean isSerializable()
@@ -306,6 +285,8 @@
   {
     this.clazz = cl;
 
+    cacheMethods();
+
     long class_uid = getClassUID(cl);
     if (uid == 0)
       uid = class_uid;
@@ -452,6 +433,50 @@
       fields[i].setOffset(objectFieldCount++);
   }
 
+  private Method findMethod(Method[] methods, String name, Class[] params,
+			    Class returnType)
+  {
+outer:
+    for(int i = 0; i < methods.length; i++)
+    {
+	if(methods[i].getName().equals(name) &&
+	   methods[i].getReturnType() == returnType)
+	{
+	    Class[] mp = methods[i].getParameterTypes();
+	    if(mp.length == params.length)
+	    {
+		for(int j = 0; j < mp.length; j++)
+		{
+		    if(mp[j] != params[j])
+		    {
+			continue outer;
+		    }
+		}
+		final Method m = methods[i];
+		AccessController.doPrivileged(new PrivilegedAction()
+		{
+		    public Object run()
+		    {
+			m.setAccessible(true);
+			return null;
+		    }
+		});
+		return m;
+	    }
+	}
+    }
+    return null;
+  }
+
+  private void cacheMethods()
+  {
+    Method[] methods = forClass().getDeclaredMethods();
+    readObjectMethod = findMethod(methods, "readObject",
+				  new Class[] { ObjectInputStream.class },
+				  Void.TYPE);
+    readResolveMethod = findMethod(methods, "readResolve",
+				   new Class[0], Object.class);
+  }
 
   private ObjectStreamClass(Class cl)
   {
@@ -460,6 +485,7 @@
     isProxyClass = Proxy.isProxyClass(cl);
 
     clazz = cl;
+    cacheMethods();
     name = cl.getName();
     setFlags(cl);
     setFields(cl);
@@ -508,9 +534,16 @@
 
     try
       {
-	Field serialPersistentFields =
+	final Field serialPersistentFields =
 	  cl.getDeclaredField("serialPersistentFields");
-	serialPersistentFields.setAccessible(true);
+	AccessController.doPrivileged(new PrivilegedAction()
+	{
+	    public Object run()
+	    {
+		serialPersistentFields.setAccessible(true);
+		return null;
+	    }
+	});
 	int modifiers = serialPersistentFields.getModifiers();
 
 	if (Modifier.isStatic(modifiers)
@@ -553,12 +586,28 @@
     for (int from = 0, to = 0; from < all_fields.length; from++)
       if (all_fields[from] != null)
 	{
-	  Field f = all_fields[from];
-	  fields[to] = new ObjectStreamField(f.getName(), f.getType());
+	  final Field f = all_fields[from];
+	  AccessController.doPrivileged(new PrivilegedAction()
+	  {
+	      public Object run()
+	      {
+		  f.setAccessible(true);
+		  return null;
+	      }
+	  });
+	  fields[to] = new ObjectStreamField(all_fields[from]);
 	  to++;
 	}
 
     Arrays.sort(fields);
+    // Make sure we don't have any duplicate field names
+    // (Sun JDK 1.4.1. throws an Internal Error as well)
+    for (int i = 1; i < fields.length; i++)
+      {
+	if(fields[i - 1].getName().equals(fields[i].getName()))
+	    throw new InternalError("Duplicate field " + 
+			fields[i].getName() + " in class " + cl.getName());
+      }
     calculateOffsets();
   }
 
@@ -571,8 +620,15 @@
 	// Use getDeclaredField rather than getField, since serialVersionUID
 	// may not be public AND we only want the serialVersionUID of this
 	// class, not a superclass or interface.
-	Field suid = cl.getDeclaredField("serialVersionUID");
-	suid.setAccessible(true);
+	final Field suid = cl.getDeclaredField("serialVersionUID");
+	AccessController.doPrivileged(new PrivilegedAction()
+	{
+	    public Object run()
+	    {
+		suid.setAccessible(true);
+		return null;
+	    }
+	});
 	int modifiers = suid.getModifiers();
 
 	if (Modifier.isStatic(modifiers)
@@ -760,6 +816,8 @@
   private String name;
   private long uid;
   private byte flags;
+  Method readObjectMethod;
+  Method readResolveMethod;
 
   // this field is package protected so that ObjectInputStream and
   // ObjectOutputStream can access it directly
Index: java/io/ObjectStreamField.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/ObjectStreamField.java,v
retrieving revision 1.12
diff -u -r1.12 ObjectStreamField.java
--- java/io/ObjectStreamField.java	27 Dec 2003 22:48:58 -0000	1.12
+++ java/io/ObjectStreamField.java	30 Jan 2004 15:01:33 -0000
@@ -38,6 +38,8 @@
 
 package java.io;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import gnu.java.lang.reflect.TypeSignature;
 
 /**
@@ -54,6 +56,14 @@
   private boolean unshared;
   private boolean persistent = false;
   private boolean toset = true;
+  private Field field;
+
+  ObjectStreamField (Field field)
+  {
+    this (field.getName(), field.getType());
+    this.field = field;
+    toset = !Modifier.isFinal(field.getModifiers());
+  }
 
   /**
    * This constructor creates an ObjectStreamField instance 
@@ -105,7 +115,6 @@
       }
     catch(ClassNotFoundException e)
       {
-        type = Object.class; //FIXME: ???
       }
   }
   
@@ -128,7 +137,6 @@
       }
     catch(ClassNotFoundException e)
       {
-        type = Object.class; // ALSO FIXME 
       }
   }
 
@@ -176,7 +184,7 @@
   public String getTypeString ()
   {
     // use intern()
-    if (this.type.isPrimitive())
+    if (isPrimitive())
       return null;
     return typename.intern();
   }
@@ -225,7 +233,7 @@
    */
   public boolean isPrimitive ()
   {
-    return type.isPrimitive ();
+    return type != null && type.isPrimitive();
   }
 
   public int compareTo (Object o)
@@ -299,5 +307,112 @@
   {
     return "ObjectStreamField< " + type + " " + name + " >";
   }
-}
 
+  final void setBooleanField(Object obj, boolean val)
+  {
+      try
+      {
+	  field.setBoolean(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setByteField(Object obj, byte val)
+  {
+      try
+      {
+	  field.setByte(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setCharField(Object obj, char val)
+  {
+      try
+      {
+	  field.setChar(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setShortField(Object obj, short val)
+  {
+      try
+      {
+	  field.setShort(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setIntField(Object obj, int val)
+  {
+      try
+      {
+	  field.setInt(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setLongField(Object obj, long val)
+  {
+      try
+      {
+	  field.setLong(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setFloatField(Object obj, float val)
+  {
+      try
+      {
+	  field.setFloat(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setDoubleField(Object obj, double val)
+  {
+      try
+      {
+	  field.setDouble(obj, val);
+      }
+      catch(IllegalAccessException x)
+      {
+	  throw new InternalError(x.getMessage());
+      }
+  }
+
+  final void setObjectField(Object obj, Object val)
+  {
+    try
+      {
+	field.set(obj, val);
+      }
+    catch(IllegalAccessException x)
+      {
+	throw new InternalError(x.getMessage());
+      }
+  }
+}
