2004-02-28 Guilhem Lavaux <guilhem@kaffe.org>
* java/io/ObjectInputStream.java (readClassDescriptor): Keep elements of the mapping non null. (checkTypeConsistency): New method. (readFields): Fixed main loop and base logic. Small reindentation. * java/io/ObjectStreamField.java (lookupField): New method to update the field reference. (checkFieldType): New method. * java/io/ObjectStreamClass.java (setClass, setFields): Call lookupField when building the field database. Check the real field type. From-SVN: r78627
This commit is contained in:
parent
ca67f27850
commit
646e329010
4 changed files with 317 additions and 173 deletions
|
@ -1,6 +1,5 @@
|
|||
/* ObjectInputStream.java -- Class used to read serialized objects
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -412,6 +411,64 @@ public class ObjectInputStream extends InputStream
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method makes a partial check of types for the fields
|
||||
* contained given in arguments. It checks primitive types of
|
||||
* fields1 against non primitive types of fields2. This method
|
||||
* assumes the two lists has already been sorted according to
|
||||
* the Java specification.
|
||||
*
|
||||
* @param name Name of the class owning the given fields.
|
||||
* @param fields1 First list to check.
|
||||
* @param fields2 Second list to check.
|
||||
* @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
|
||||
* in the non primitive part in fields2.
|
||||
*/
|
||||
private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
|
||||
throws InvalidClassException
|
||||
int nonPrimitive = 0;
|
||||
|
||||
for (nonPrimitive = 0;
|
||||
nonPrimitive < fields1.length
|
||||
&& fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
|
||||
{
|
||||
}
|
||||
|
||||
if (nonPrimitive == fields1.length)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
ObjectStreamField f1;
|
||||
ObjectStreamField f2;
|
||||
|
||||
while (i < fields2.length
|
||||
&& nonPrimitive < fields1.length)
|
||||
{
|
||||
f1 = fields1[nonPrimitive];
|
||||
f2 = fields2[i];
|
||||
|
||||
if (!f2.isPrimitive())
|
||||
break;
|
||||
|
||||
int compVal = f1.getName().compareTo (f2.getName());
|
||||
|
||||
if (compVal < 0)
|
||||
{
|
||||
nonPrimitive++;
|
||||
}
|
||||
else if (compVal > 0)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidClassException
|
||||
("invalid field type for " + f2.getName() +
|
||||
" in class " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method reads a class descriptor from the real input stream
|
||||
* and use these data to create a new instance of ObjectStreamClass.
|
||||
|
@ -497,6 +554,15 @@ public class ObjectInputStream extends InputStream
|
|||
int real_idx = 0;
|
||||
int map_idx = 0;
|
||||
|
||||
/*
|
||||
* Check that there is no type inconsistencies between the lists.
|
||||
* A special checking must be done for the two groups: primitive types and
|
||||
* not primitive types.
|
||||
*/
|
||||
checkTypeConsistency(name, real_fields, stream_fields);
|
||||
checkTypeConsistency(name, stream_fields, real_fields);
|
||||
|
||||
|
||||
while (stream_idx < stream_fields.length
|
||||
|| real_idx < real_fields.length)
|
||||
{
|
||||
|
@ -514,7 +580,7 @@ public class ObjectInputStream extends InputStream
|
|||
else
|
||||
{
|
||||
int comp_val =
|
||||
real_fields[real_idx].compareTo (stream_fields[stream_idx]);
|
||||
real_fields[real_idx].compareTo (stream_fields[stream_idx]);
|
||||
|
||||
if (comp_val < 0)
|
||||
{
|
||||
|
@ -528,21 +594,13 @@ public class ObjectInputStream extends InputStream
|
|||
{
|
||||
stream_field = stream_fields[stream_idx++];
|
||||
real_field = real_fields[real_idx++];
|
||||
if(stream_field.getType() != real_field.getType())
|
||||
throw new InvalidClassException
|
||||
("invalid field type for " + real_field.getName() +
|
||||
" in class " + name);
|
||||
if (stream_field.getType() != real_field.getType())
|
||||
throw new InvalidClassException
|
||||
("invalid field type for " + real_field.getName() +
|
||||
" in class " + name);
|
||||
}
|
||||
}
|
||||
if (stream_field != null)
|
||||
{
|
||||
if (stream_field.getOffset() < 0)
|
||||
stream_field = null;
|
||||
else if (!stream_field.isToSet())
|
||||
real_field = null;
|
||||
}
|
||||
if (real_field != null && !real_field.isToSet())
|
||||
real_field = null;
|
||||
|
||||
/* If some of stream_fields does not correspond to any of real_fields,
|
||||
* or the opposite, then fieldmapping will go short.
|
||||
*/
|
||||
|
@ -551,7 +609,7 @@ public class ObjectInputStream extends InputStream
|
|||
ObjectStreamField[] newfieldmapping =
|
||||
new ObjectStreamField[fieldmapping.length + 2];
|
||||
System.arraycopy(fieldmapping, 0,
|
||||
newfieldmapping, 0, fieldmapping.length);
|
||||
newfieldmapping, 0, fieldmapping.length);
|
||||
fieldmapping = newfieldmapping;
|
||||
}
|
||||
fieldmapping[map_idx++] = stream_field;
|
||||
|
@ -1577,121 +1635,119 @@ public class ObjectInputStream extends InputStream
|
|||
{
|
||||
ObjectStreamField stream_field = fields[i];
|
||||
ObjectStreamField real_field = fields[i + 1];
|
||||
if(stream_field != null || real_field != null)
|
||||
{
|
||||
boolean read_value = stream_field != null;
|
||||
boolean set_value = real_field != null;
|
||||
String field_name;
|
||||
char type;
|
||||
if (stream_field != null)
|
||||
{
|
||||
field_name = stream_field.getName();
|
||||
type = stream_field.getTypeCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
field_name = real_field.getName();
|
||||
type = real_field.getTypeCode();
|
||||
}
|
||||
boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
|
||||
boolean set_value = (real_field != null && real_field.isToSet());
|
||||
String field_name;
|
||||
char type;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 'Z':
|
||||
{
|
||||
boolean value =
|
||||
read_value ? this.realInputStream.readBoolean() : false;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setBooleanField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'B':
|
||||
{
|
||||
byte value =
|
||||
read_value ? this.realInputStream.readByte() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setByteField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'C':
|
||||
{
|
||||
char value =
|
||||
read_value ? this.realInputStream.readChar(): 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setCharField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'D':
|
||||
{
|
||||
double value =
|
||||
read_value ? this.realInputStream.readDouble() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setDoubleField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'F':
|
||||
{
|
||||
float value =
|
||||
read_value ? this.realInputStream.readFloat() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setFloatField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'I':
|
||||
{
|
||||
int value =
|
||||
read_value ? this.realInputStream.readInt() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setIntField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'J':
|
||||
{
|
||||
long value =
|
||||
read_value ? this.realInputStream.readLong() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setLongField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'S':
|
||||
{
|
||||
short value =
|
||||
read_value ? this.realInputStream.readShort() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setShortField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case '[':
|
||||
{
|
||||
Object value =
|
||||
read_value ? readObject() : null;
|
||||
if (set_value)
|
||||
real_field.setObjectField(obj, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Invalid type code: " + type);
|
||||
}
|
||||
if (stream_field != null)
|
||||
{
|
||||
field_name = stream_field.getName();
|
||||
type = stream_field.getTypeCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
field_name = real_field.getName();
|
||||
type = real_field.getTypeCode();
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 'Z':
|
||||
{
|
||||
boolean value =
|
||||
read_value ? this.realInputStream.readBoolean() : false;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setBooleanField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'B':
|
||||
{
|
||||
byte value =
|
||||
read_value ? this.realInputStream.readByte() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setByteField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'C':
|
||||
{
|
||||
char value =
|
||||
read_value ? this.realInputStream.readChar(): 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setCharField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'D':
|
||||
{
|
||||
double value =
|
||||
read_value ? this.realInputStream.readDouble() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setDoubleField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'F':
|
||||
{
|
||||
float value =
|
||||
read_value ? this.realInputStream.readFloat() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setFloatField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'I':
|
||||
{
|
||||
int value =
|
||||
read_value ? this.realInputStream.readInt() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setIntField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'J':
|
||||
{
|
||||
long value =
|
||||
read_value ? this.realInputStream.readLong() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setLongField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'S':
|
||||
{
|
||||
short value =
|
||||
read_value ? this.realInputStream.readShort() : 0;
|
||||
if (dump && read_value && set_value)
|
||||
dumpElementln(" " + field_name + ": " + value);
|
||||
if (set_value)
|
||||
real_field.setShortField(obj, value);
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case '[':
|
||||
{
|
||||
Object value =
|
||||
read_value ? readObject() : null;
|
||||
if (set_value)
|
||||
real_field.setObjectField(obj, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Invalid type code: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Toggles writing primitive data to block-data buffer.
|
||||
private boolean setBlockDataMode (boolean on)
|
||||
{
|
||||
|
|
|
@ -327,7 +327,7 @@ public class ObjectStreamClass implements Serializable
|
|||
i = 0; j = 0; k = 0;
|
||||
while (i < fields.length && j < exportedFields.length)
|
||||
{
|
||||
int comp = fields[i].getName().compareTo(exportedFields[j].getName());
|
||||
int comp = fields[i].compareTo(exportedFields[j]);
|
||||
|
||||
if (comp < 0)
|
||||
{
|
||||
|
@ -344,10 +344,27 @@ public class ObjectStreamClass implements Serializable
|
|||
newFieldList[k] = exportedFields[j];
|
||||
newFieldList[k].setPersistent(true);
|
||||
newFieldList[k].setToSet(false);
|
||||
try
|
||||
{
|
||||
newFieldList[k].lookupField(clazz);
|
||||
newFieldList[k].checkFieldType();
|
||||
}
|
||||
catch (NoSuchFieldException _)
|
||||
{
|
||||
}
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
exportedFields[j].lookupField(clazz);
|
||||
exportedFields[j].checkFieldType();
|
||||
}
|
||||
catch (NoSuchFieldException _)
|
||||
{
|
||||
}
|
||||
|
||||
if (!fields[i].getType().equals(exportedFields[j].getType()))
|
||||
throw new InvalidClassException
|
||||
("serialPersistentFields must be compatible with" +
|
||||
|
@ -554,6 +571,19 @@ outer:
|
|||
if (fields != null)
|
||||
{
|
||||
Arrays.sort (fields);
|
||||
// Retrieve field reference.
|
||||
for (int i=0; i < fields.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
fields[i].lookupField(cl);
|
||||
}
|
||||
catch (NoSuchFieldException _)
|
||||
{
|
||||
fields[i].setToSet(false);
|
||||
}
|
||||
}
|
||||
|
||||
calculateOffsets();
|
||||
return;
|
||||
}
|
||||
|
@ -798,7 +828,7 @@ outer:
|
|||
|
||||
fieldsArray = new ObjectStreamField[ o.length ];
|
||||
System.arraycopy(o, 0, fieldsArray, 0, o.length);
|
||||
|
||||
|
||||
return fieldsArray;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ package java.io;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import gnu.java.lang.reflect.TypeSignature;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* This class intends to describe the field of a class for the serialization
|
||||
|
@ -99,7 +101,7 @@ public class ObjectStreamField implements Comparable
|
|||
|
||||
/**
|
||||
* There are many cases you can not get java.lang.Class from typename
|
||||
* if your context class loader cann not load it, then use typename to
|
||||
* if your context class loader cannot load it, then use typename to
|
||||
* construct the field.
|
||||
*
|
||||
* @param name Name of the field to export.
|
||||
|
@ -292,7 +294,7 @@ public class ObjectStreamField implements Comparable
|
|||
}
|
||||
|
||||
/**
|
||||
* This methods returns true if the field is marked as to be
|
||||
* This method returns true if the field is marked as to be
|
||||
* set.
|
||||
*
|
||||
* @return True if it is to be set, false in the other cases.
|
||||
|
@ -303,6 +305,49 @@ public class ObjectStreamField implements Comparable
|
|||
return toset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method searches for its field reference in the specified class
|
||||
* object. It requests privileges. If an error occurs the internal field
|
||||
* reference is not modified.
|
||||
*
|
||||
* @throws NoSuchFieldException if the field name does not exist in this class.
|
||||
* @throws SecurityException if there was an error requesting the privileges.
|
||||
*/
|
||||
void lookupField(Class clazz) throws NoSuchFieldException, SecurityException
|
||||
{
|
||||
final Field f = clazz.getDeclaredField(name);
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
f.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
this.field = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method check whether the field described by this
|
||||
* instance of ObjectStreamField is compatible with the
|
||||
* actual implementation of this field.
|
||||
*
|
||||
* @throws NullPointerException if this field does not exist
|
||||
* in the real class.
|
||||
* @throws InvalidClassException if the types are incompatible.
|
||||
*/
|
||||
void checkFieldType() throws InvalidClassException
|
||||
{
|
||||
Class ftype = field.getType();
|
||||
|
||||
if (!ftype.isAssignableFrom(type))
|
||||
throw new InvalidClassException
|
||||
("invalid field type for " + name +
|
||||
" in class " + field.getDeclaringClass());
|
||||
}
|
||||
|
||||
public String toString ()
|
||||
{
|
||||
return "ObjectStreamField< " + type + " " + name + " >";
|
||||
|
@ -310,102 +355,102 @@ public class ObjectStreamField implements Comparable
|
|||
|
||||
final void setBooleanField(Object obj, boolean val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setBoolean(obj, val);
|
||||
field.setBoolean(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setByteField(Object obj, byte val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setByte(obj, val);
|
||||
field.setByte(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setCharField(Object obj, char val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setChar(obj, val);
|
||||
field.setChar(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setShortField(Object obj, short val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setShort(obj, val);
|
||||
field.setShort(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setIntField(Object obj, int val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setInt(obj, val);
|
||||
field.setInt(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setLongField(Object obj, long val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setLong(obj, val);
|
||||
field.setLong(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setFloatField(Object obj, float val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setFloat(obj, val);
|
||||
field.setFloat(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setDoubleField(Object obj, double val)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
field.setDouble(obj, val);
|
||||
field.setDouble(obj, val);
|
||||
}
|
||||
catch(IllegalAccessException x)
|
||||
catch(IllegalAccessException x)
|
||||
{
|
||||
throw new InternalError(x.getMessage());
|
||||
throw new InternalError(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void setObjectField(Object obj, Object val)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
field.set(obj, val);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue