This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

FYI: Patch: java.io: ObjectInputStream and ObjectStreamClass


Hi list,


I commited the attached patch from Guilhem Lavaux. This patch was okayed for 
classpath but not yet commited because of the hack.


Michael
Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/libjava/ChangeLog,v
retrieving revision 1.2444
diff -u -b -B -r1.2444 ChangeLog
--- ChangeLog	16 Dec 2003 12:19:32 -0000	1.2444
+++ ChangeLog	16 Dec 2003 13:42:01 -0000
@@ -1,3 +1,17 @@
+i2003-12-16  Guilhem Lavaux <guilhem@kaffe.org>
+
+	* java/io/ObjectInputStream.java
+	(lookupClass): New method.
+	(currentLoader): New method.
+	(inputGetObjectStreamClasses): New method.
+	(assignNewHandle): Documented.
+	(currentClassLoader): Documented.
+	* java/io/ObjectStreamClass.java
+	(setClass): Changed API. Better handling of the imported/exported
+	fields.
+	(getSerialPersistentFields): Make it throw previously caught exceptions
+	so they can handled in setClass.
+
 2003-12-16 Guilhem Lavaux <guilhem@kaffe.org>
  
 	* java/io/ObjectStreamField.java: A few methods were added in prevision
Index: java/io/ObjectStreamClass.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamClass.java,v
retrieving revision 1.15
diff -u -b -B -r1.15 ObjectStreamClass.java
--- java/io/ObjectStreamClass.java	11 Oct 2003 18:38:12 -0000	1.15
+++ java/io/ObjectStreamClass.java	16 Dec 2003 13:42:01 -0000
@@ -291,7 +291,18 @@
     this.fields = fields;
   }
 
-  void setClass (Class cl) throws InvalidClassException
+  /**
+   * This method builds the internal description corresponding to a Java Class.
+   * As the constructor only assign a name to the current ObjectStreamClass instance,
+   * that method sets the serial UID, chose the fields which will be serialized,
+   * and compute the position of the fields in the serialized stream.
+   *
+   * @param cl The Java class which is used as a reference for building the descriptor.
+   * @param superClass The descriptor of the super class for this class descriptor.
+   * @throws InvalidClassException if an incompatibility between computed UID and
+   * already set UID is found.
+   */
+  void setClass (Class cl, ObjectStreamClass superClass) throws InvalidClassException
   {
     this.clazz = cl;
 
@@ -312,11 +323,87 @@
       }
 
     isProxyClass = clazz != null && Proxy.isProxyClass (clazz);
-    ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (clazz);
-    if (osc == null)
-      classLookupTable.put (clazz, this);
-    superClass = lookupForClassObject (clazz.getSuperclass ());
+    this.superClass = superClass;
     calculateOffsets ();
+
+    try
+      {
+        ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz);
+
+        if (exportedFields == null)
+          return;
+
+        ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
+        int i, j, k;
+
+        /* We now check the import fields against the exported fields.
+         * There should not be contradiction (e.g. int x and String x)
+         * but extra virtual fields can be added to the class.
+         */
+
+        Arrays.sort(exportedFields);
+
+        i = 0; j = 0; k = 0;
+        while (i < fields.length && j < exportedFields.length)
+          {
+            int comp = fields[i].getName().compareTo (exportedFields[j].getName());
+            if (comp < 0)
+              {
+                newFieldList[k] = fields[i];
+                fields[i].setPersistent(false);
+                fields[i].setToSet(false);
+                i++;
+              }
+            else if (comp > 0)
+              {
+                /* field not found in imported fields. We add it
+                 * in the list of supported fields.
+                 */
+                newFieldList[k] = exportedFields[j];
+                newFieldList[k].setPersistent(true);
+                newFieldList[k].setToSet(false);
+                j++;
+              }
+            else
+              {
+                if (!fields[i].getType().equals (exportedFields[j].getType()))
+                  throw new InvalidClassException ("serialPersistentFields must be compatible with" +
+                                                   " imported fields (about " + fields[i].getName() + ")");
+                newFieldList[k] = fields[i];
+                fields[i].setPersistent(true);
+                i++;
+                j++;
+              }
+            k++;
+          }
+
+        if (i < fields.length)
+          for (; i < fields.length; i++, k++)
+            {
+              fields[i].setPersistent(false);
+              fields[i].setToSet(false);
+              newFieldList[k] = fields[i];
+            }
+          else
+            if (j < exportedFields.length)
+              for (; j < exportedFields.length; j++, k++)
+                {
+                  exportedFields[j].setPersistent(true);
+                  exportedFields[j].setToSet(false);
+                  newFieldList[k] = exportedFields[j];
+               }
+
+        fields = new ObjectStreamField[k];
+        System.arraycopy (newFieldList, 0, fields, 0, k);
+      }
+    catch (NoSuchFieldException ignore)
+      {
+        return;
+      }
+    catch (IllegalAccessException ignore)
+      {
+        return;
+      }
   }
 
   void setSuperclass (ObjectStreamClass osc)
@@ -436,6 +523,9 @@
     }
     catch (NoSuchFieldException ignore)
     {}
+    catch (IllegalAccessException ignore)
+      {
+      }
 
     int num_good_fields = 0;
     Field[] all_fields = cl.getDeclaredFields ();
@@ -613,24 +703,13 @@
   // Returns the value of CLAZZ's private static final field named
   // `serialPersistentFields'.
   private ObjectStreamField[] getSerialPersistentFields (Class clazz)
-  {
-    ObjectStreamField[] o = null;
-    try
+    throws NoSuchFieldException, IllegalAccessException
       {
 	// Use getDeclaredField rather than getField for the same reason
 	// as above in getDefinedSUID.
-	Field f = clazz.getDeclaredField ("serialPersistentFields");
+    Field f = clazz.getDeclaredField("serialPersistentFields");
 	f.setAccessible(true);
-	o = (ObjectStreamField[])f.get (null);
-      }
-    catch (java.lang.NoSuchFieldException e)
-      {
-      }
-    catch (java.lang.IllegalAccessException e)
-      {
-      }
-
-    return o;
+    return (ObjectStreamField[]) f.get(null);
   }
 
   public static final ObjectStreamField[] NO_FIELDS = {};
Index: java/io/ObjectInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectInputStream.java,v
retrieving revision 1.21
diff -u -b -B -r1.21 ObjectInputStream.java
--- java/io/ObjectInputStream.java	16 Dec 2003 11:46:23 -0000	1.21
+++ java/io/ObjectInputStream.java	16 Dec 2003 13:42:01 -0000
@@ -203,7 +203,7 @@
 	      Class cl = resolveProxyClass(intfs);
 	      setBlockDataMode(oldmode);
 	      
-	      ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
+	      ObjectStreamClass osc = lookupClass(cl);
 	      assignNewHandle (osc);
 	      
 	      if (!is_consumed)
@@ -332,7 +332,7 @@
 	      int handle = assignNewHandle (obj);
 	      this.currentObject = obj;
 	      ObjectStreamClass[] hierarchy =
-		ObjectStreamClass.getObjectStreamClasses (clazz);
+		inputGetObjectStreamClasses(clazz);
 	      
 	      for (int i=0; i < hierarchy.length; i++)
 		{
@@ -455,8 +455,10 @@
 	  new ObjectStreamField (field_name, class_name);
       }
 	      
+    Class clazz = resolveClass(osc);
     boolean oldmode = setBlockDataMode (true);
-    osc.setClass (resolveClass (osc));
+    osc.setClass (clazz, lookupClass(clazz.getSuperclass()));
+    classLookupTable.put(clazz, osc);
     setBlockDataMode (oldmode);
 	      
     return osc;
@@ -550,19 +552,78 @@
   protected Class resolveClass (ObjectStreamClass osc)
     throws ClassNotFoundException, IOException
   {
+    return Class.forName(osc.getName(), true, currentLoader());
+  }
+
+  private ClassLoader currentLoader()
+  {
     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 currentClassLoader(sm);
+  }
+
+  /**
+   * Lookup a class stored in the local hashtable. If it is not
+   * use the global lookup function in ObjectStreamClass to build
+   * the ObjectStreamClass. This method is requested according to
+   * the behaviour detected in the JDK by Kaffe's team.
+   *
+   * @param clazz Class to lookup in the hash table or for which
+   * we must build a descriptor.
+   * @return A valid instance of ObjectStreamClass corresponding
+   * to the specified class.
+   */
+  private ObjectStreamClass lookupClass (Class clazz)
+  {
+    ObjectStreamClass oclazz;
 
-    if (cl == null)
-      return Class.forName (osc.getName ());
+    oclazz = (ObjectStreamClass) classLookupTable.get(clazz);
+    if (oclazz == null)
+      return ObjectStreamClass.lookup (clazz);
     else
-      return cl.loadClass (osc.getName ());
+      return oclazz;
+  }
+
+  /**
+   * Reconstruct class hierarchy the same way
+   * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does
+   * but using lookupClass instead of ObjectStreamClass.lookup. This
+   * dup is necessary localize the lookup table. Hopefully some future rewritings will
+   * be able to prevent this.
+   *
+   * @param clazz This is the class for which we want the hierarchy.
+   *
+   * @return An array of valid {@link java.io.ObjectStreamClass} instances which
+   * represent the class hierarchy for clazz.
+   */
+  private ObjectStreamClass[] inputGetObjectStreamClasses (Class clazz)
+  {
+    ObjectStreamClass osc = lookupClass (clazz);
+
+    ObjectStreamClass[] ret_val;
+
+    if (osc == null)
+      return new ObjectStreamClass[0];
+    else
+      {
+        Vector oscs = new Vector();
+
+        while (osc != null)
+          {
+            oscs.addElement(osc);
+            osc = osc.getSuper();
+	  }
+
+        int count = oscs.size();
+	ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
+
+        for (int i = count - 1; i >= 0; i--)
+          sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
+
+        return sorted_oscs;
+      }
   }
 
   /**
@@ -1061,7 +1122,12 @@
     throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
   }
 
-  // assigns the next availible handle to OBJ
+  /**
+   * Assigns the next available handle to <code>obj</code>.
+   *
+   * @param obj The object for which we want a new handle.
+   * @return A valid handle for the specified object.
+   */
   private int assignNewHandle (Object obj)
   {
     this.objectLookupTable.put (new Integer (this.nextOID),
@@ -1213,7 +1279,7 @@
   {
     ObjectStreamField[] stream_fields = stream_osc.fields;
     ObjectStreamField[] real_fields =
-      ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
+      lookupClass(stream_osc.forClass()).fields;
 
     boolean default_initialize, set_value;
     String field_name = null;
@@ -1406,8 +1472,13 @@
       }
   }
 
-  // this native method is used to get access to the protected method
-  // of the same name in SecurityManger
+  /**
+   * This native method is used to get access to the protected method
+   * of the same name in SecurityManger.
+   *
+   * @param sm SecurityManager instance which should be called.
+   * @return The current class loader in the calling stack.
+   */
   private static ClassLoader currentClassLoader (SecurityManager sm)
   {
     // FIXME: This is too simple.
@@ -1757,6 +1828,7 @@
   private boolean isDeserializing;
   private boolean fieldsAlreadyRead;
   private Vector validators;
+  private Hashtable classLookupTable;
 
   private static boolean dump;
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]