From: Guilhem Lavaux Date: Tue, 16 Dec 2003 13:45:01 +0000 (+0000) Subject: i2003-12-16 Guilhem Lavaux X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=649a1a476c573b145a2af341f30755d2c4edf10b;p=gcc.git i2003-12-16 Guilhem Lavaux * 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. From-SVN: r74693 --- diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 6eeda359e8d..05d0fb89382 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,17 @@ +i2003-12-16 Guilhem Lavaux + + * 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 * java/io/ObjectStreamField.java: A few methods were added in prevision diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index c11299efcb4..974b12df0c2 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -203,7 +203,7 @@ public class ObjectInputStream extends InputStream Class cl = resolveProxyClass(intfs); setBlockDataMode(oldmode); - ObjectStreamClass osc = ObjectStreamClass.lookup(cl); + ObjectStreamClass osc = lookupClass(cl); assignNewHandle (osc); if (!is_consumed) @@ -332,7 +332,7 @@ public class ObjectInputStream extends InputStream 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 @@ public class ObjectInputStream extends InputStream 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; @@ -549,20 +551,79 @@ public class ObjectInputStream extends InputStream */ 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 () {}; + + return currentClassLoader(sm); + } - // 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); + /** + * 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 @@ public class ObjectInputStream extends InputStream throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride"); } - // assigns the next availible handle to OBJ + /** + * Assigns the next available handle to obj. + * + * @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 @@ public class ObjectInputStream extends InputStream { 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 @@ public class ObjectInputStream extends InputStream } } - // 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 @@ public class ObjectInputStream extends InputStream private boolean isDeserializing; private boolean fieldsAlreadyRead; private Vector validators; + private Hashtable classLookupTable; private static boolean dump; diff --git a/libjava/java/io/ObjectStreamClass.java b/libjava/java/io/ObjectStreamClass.java index 3a2ccfb8e99..0be9a7e5053 100644 --- a/libjava/java/io/ObjectStreamClass.java +++ b/libjava/java/io/ObjectStreamClass.java @@ -291,7 +291,18 @@ public class ObjectStreamClass implements Serializable 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 @@ public class ObjectStreamClass implements Serializable } 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 @@ public class ObjectStreamClass implements Serializable } catch (NoSuchFieldException ignore) {} + catch (IllegalAccessException ignore) + { + } int num_good_fields = 0; Field[] all_fields = cl.getDeclaredFields (); @@ -613,24 +703,13 @@ public class ObjectStreamClass implements Serializable // Returns the value of CLAZZ's private static final field named // `serialPersistentFields'. private ObjectStreamField[] getSerialPersistentFields (Class clazz) + throws NoSuchFieldException, IllegalAccessException { - ObjectStreamField[] o = null; - try - { - // Use getDeclaredField rather than getField for the same reason - // as above in getDefinedSUID. - 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; + // Use getDeclaredField rather than getField for the same reason + // as above in getDefinedSUID. + Field f = clazz.getDeclaredField("serialPersistentFields"); + f.setAccessible(true); + return (ObjectStreamField[]) f.get(null); } public static final ObjectStreamField[] NO_FIELDS = {};