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. From-SVN: r74693
This commit is contained in:
parent
b1660ae9ea
commit
649a1a476c
3 changed files with 201 additions and 36 deletions
|
@ -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>
|
2003-12-16 Guilhem Lavaux <guilhem@kaffe.org>
|
||||||
|
|
||||||
* java/io/ObjectStreamField.java: A few methods were added in prevision
|
* java/io/ObjectStreamField.java: A few methods were added in prevision
|
||||||
|
|
|
@ -203,7 +203,7 @@ public class ObjectInputStream extends InputStream
|
||||||
Class cl = resolveProxyClass(intfs);
|
Class cl = resolveProxyClass(intfs);
|
||||||
setBlockDataMode(oldmode);
|
setBlockDataMode(oldmode);
|
||||||
|
|
||||||
ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
|
ObjectStreamClass osc = lookupClass(cl);
|
||||||
assignNewHandle (osc);
|
assignNewHandle (osc);
|
||||||
|
|
||||||
if (!is_consumed)
|
if (!is_consumed)
|
||||||
|
@ -332,7 +332,7 @@ public class ObjectInputStream extends InputStream
|
||||||
int handle = assignNewHandle (obj);
|
int handle = assignNewHandle (obj);
|
||||||
this.currentObject = obj;
|
this.currentObject = obj;
|
||||||
ObjectStreamClass[] hierarchy =
|
ObjectStreamClass[] hierarchy =
|
||||||
ObjectStreamClass.getObjectStreamClasses (clazz);
|
inputGetObjectStreamClasses(clazz);
|
||||||
|
|
||||||
for (int i=0; i < hierarchy.length; i++)
|
for (int i=0; i < hierarchy.length; i++)
|
||||||
{
|
{
|
||||||
|
@ -455,8 +455,10 @@ public class ObjectInputStream extends InputStream
|
||||||
new ObjectStreamField (field_name, class_name);
|
new ObjectStreamField (field_name, class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class clazz = resolveClass(osc);
|
||||||
boolean oldmode = setBlockDataMode (true);
|
boolean oldmode = setBlockDataMode (true);
|
||||||
osc.setClass (resolveClass (osc));
|
osc.setClass (clazz, lookupClass(clazz.getSuperclass()));
|
||||||
|
classLookupTable.put(clazz, osc);
|
||||||
setBlockDataMode (oldmode);
|
setBlockDataMode (oldmode);
|
||||||
|
|
||||||
return osc;
|
return osc;
|
||||||
|
@ -549,20 +551,79 @@ public class ObjectInputStream extends InputStream
|
||||||
*/
|
*/
|
||||||
protected Class resolveClass (ObjectStreamClass osc)
|
protected Class resolveClass (ObjectStreamClass osc)
|
||||||
throws ClassNotFoundException, IOException
|
throws ClassNotFoundException, IOException
|
||||||
|
{
|
||||||
|
return Class.forName(osc.getName(), true, currentLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassLoader currentLoader()
|
||||||
{
|
{
|
||||||
SecurityManager sm = System.getSecurityManager ();
|
SecurityManager sm = System.getSecurityManager ();
|
||||||
if (sm == null)
|
if (sm == null)
|
||||||
sm = new SecurityManager () {};
|
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
|
* Lookup a class stored in the local hashtable. If it is not
|
||||||
// readObject(). See SecurityManager.getClassContext().
|
* use the global lookup function in ObjectStreamClass to build
|
||||||
ClassLoader cl = currentClassLoader (sm);
|
* 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)
|
oclazz = (ObjectStreamClass) classLookupTable.get(clazz);
|
||||||
return Class.forName (osc.getName ());
|
if (oclazz == null)
|
||||||
|
return ObjectStreamClass.lookup (clazz);
|
||||||
else
|
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");
|
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)
|
private int assignNewHandle (Object obj)
|
||||||
{
|
{
|
||||||
this.objectLookupTable.put (new Integer (this.nextOID),
|
this.objectLookupTable.put (new Integer (this.nextOID),
|
||||||
|
@ -1213,7 +1279,7 @@ public class ObjectInputStream extends InputStream
|
||||||
{
|
{
|
||||||
ObjectStreamField[] stream_fields = stream_osc.fields;
|
ObjectStreamField[] stream_fields = stream_osc.fields;
|
||||||
ObjectStreamField[] real_fields =
|
ObjectStreamField[] real_fields =
|
||||||
ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
|
lookupClass(stream_osc.forClass()).fields;
|
||||||
|
|
||||||
boolean default_initialize, set_value;
|
boolean default_initialize, set_value;
|
||||||
String field_name = null;
|
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)
|
private static ClassLoader currentClassLoader (SecurityManager sm)
|
||||||
{
|
{
|
||||||
// FIXME: This is too simple.
|
// FIXME: This is too simple.
|
||||||
|
@ -1757,6 +1828,7 @@ public class ObjectInputStream extends InputStream
|
||||||
private boolean isDeserializing;
|
private boolean isDeserializing;
|
||||||
private boolean fieldsAlreadyRead;
|
private boolean fieldsAlreadyRead;
|
||||||
private Vector validators;
|
private Vector validators;
|
||||||
|
private Hashtable classLookupTable;
|
||||||
|
|
||||||
private static boolean dump;
|
private static boolean dump;
|
||||||
|
|
||||||
|
|
|
@ -291,7 +291,18 @@ public class ObjectStreamClass implements Serializable
|
||||||
this.fields = fields;
|
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;
|
this.clazz = cl;
|
||||||
|
|
||||||
|
@ -312,11 +323,87 @@ public class ObjectStreamClass implements Serializable
|
||||||
}
|
}
|
||||||
|
|
||||||
isProxyClass = clazz != null && Proxy.isProxyClass (clazz);
|
isProxyClass = clazz != null && Proxy.isProxyClass (clazz);
|
||||||
ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (clazz);
|
this.superClass = superClass;
|
||||||
if (osc == null)
|
|
||||||
classLookupTable.put (clazz, this);
|
|
||||||
superClass = lookupForClassObject (clazz.getSuperclass ());
|
|
||||||
calculateOffsets ();
|
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)
|
void setSuperclass (ObjectStreamClass osc)
|
||||||
|
@ -436,6 +523,9 @@ public class ObjectStreamClass implements Serializable
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException ignore)
|
catch (NoSuchFieldException ignore)
|
||||||
{}
|
{}
|
||||||
|
catch (IllegalAccessException ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int num_good_fields = 0;
|
int num_good_fields = 0;
|
||||||
Field[] all_fields = cl.getDeclaredFields ();
|
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
|
// Returns the value of CLAZZ's private static final field named
|
||||||
// `serialPersistentFields'.
|
// `serialPersistentFields'.
|
||||||
private ObjectStreamField[] getSerialPersistentFields (Class clazz)
|
private ObjectStreamField[] getSerialPersistentFields (Class clazz)
|
||||||
|
throws NoSuchFieldException, IllegalAccessException
|
||||||
{
|
{
|
||||||
ObjectStreamField[] o = null;
|
// Use getDeclaredField rather than getField for the same reason
|
||||||
try
|
// as above in getDefinedSUID.
|
||||||
{
|
Field f = clazz.getDeclaredField("serialPersistentFields");
|
||||||
// Use getDeclaredField rather than getField for the same reason
|
f.setAccessible(true);
|
||||||
// as above in getDefinedSUID.
|
return (ObjectStreamField[]) f.get(null);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final ObjectStreamField[] NO_FIELDS = {};
|
public static final ObjectStreamField[] NO_FIELDS = {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue