Class cl = resolveProxyClass(intfs);
setBlockDataMode(oldmode);
- ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
+ ObjectStreamClass osc = lookupClass(cl);
assignNewHandle (osc);
if (!is_consumed)
int handle = assignNewHandle (obj);
this.currentObject = obj;
ObjectStreamClass[] hierarchy =
- ObjectStreamClass.getObjectStreamClasses (clazz);
+ inputGetObjectStreamClasses(clazz);
for (int i=0; i < hierarchy.length; i++)
{
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;
*/
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;
+ }
}
/**
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),
{
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;
}
}
- // 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.
private boolean isDeserializing;
private boolean fieldsAlreadyRead;
private Vector validators;
+ private Hashtable classLookupTable;
private static boolean dump;
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;
}
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)
}
catch (NoSuchFieldException ignore)
{}
+ catch (IllegalAccessException ignore)
+ {
+ }
int num_good_fields = 0;
Field[] all_fields = cl.getDeclaredFields ();
// 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 = {};