Hi,
Here is the last patch on serialization.
This patch fixes the behaviour of readFields() in ObjectInputStream:
* if called multiple times read fields and build field decoder only once.
* more documentation
* GetField methods should take into account the flags concerning
each serialized fields. If transient we have to make it return
a default value, if not we try to get it in the pool of read fields.
If the field doesn't exist we should throw an exception.
ChangeLog entry:
2003-12-07 Guilhem Lavaux <[EMAIL PROTECTED]>
* java/io/ObjectInputStream.java:
(readFields): Changed implementation of GetField.
(readClassDescriptor): Documented.
Cheers,
Guilhem.
--- java/io/ObjectInputStream.java.orig 2003-12-04 19:36:56.0 +0100
+++ java/io/ObjectInputStream.java 2003-12-04 19:57:15.0 +0100
@@ -417,6 +417,22 @@
return ret_val;
}
+ /**
+ * This method reads a class descriptor from the real input stream
+ * and use these data to create a new instance of ObjectStreamClass.
+ * Fields are sorted and ordered for the real read which occurs for
+ * each instance of the described class. Be aware that if you call that
+ * method you must ensure that the stream is synchronized, in the other
+ * case it may be completely desynchronized.
+ *
+ * @return A new instance of ObjectStreamClass containing the freshly
+ * created descriptor.
+ * @throws ClassNotFoundException if the required class to build the
+ * descriptor has not been found in the system.
+ * @throws IOException An input/output error occured.
+ * @throws InvalidClassException If there was a compatibility problem
+ * between the class present in the system and the serialized class.
+ */
protected ObjectStreamClass readClassDescriptor ()
throws ClassNotFoundException, IOException
{
@@ -585,7 +601,15 @@
{
return Class.forName (osc.getName(), true, currentLoader());
}
-
+
+ /**
+ * This method invokes the method currentClassLoader for the
+ * current security manager (or build an empty one if it is not
+ * present).
+ *
+ * @return The most recent non-system ClassLoader on the execution stack.
+ * @see java.lang.SecurityManager#currentClassLoader()
+ */
private ClassLoader currentLoader ()
{
SecurityManager sm = System.getSecurityManager ();
@@ -1014,14 +1038,31 @@
throws IOException, IllegalArgumentException;
}
+ /**
+ * This method should be called by a method called 'readObject' in the
+ * deserializing class (if present). It cannot (and should not)be called
+ * outside of it. Its goal is to read all fields in the real input stream
+ * and keep them accessible through the [EMAIL PROTECTED] #GetField} class. Calling
+ * this method will not alterate the deserializing object.
+ *
+ * @return A valid freshly created 'GetField' instance to get access to
+ * the deserialized stream.
+ * @throws IOException An input/output exception occured.
+ * @throws ClassNotFoundException
+ * @throws NotActiveException
+ */
public GetField readFields ()
throws IOException, ClassNotFoundException, NotActiveException
{
if (this.currentObject == null || this.currentObjectStreamClass == null)
throw new NotActiveException ("readFields called by non-active class and/or
object");
+if (prereadFields != null)
+ return prereadFields;
+
if (fieldsAlreadyRead)
- throw new NotActiveException ("readFields called but fields already read from
stream (by defaultReadObject or readFields)");
+ throw new NotActiveException ("readFields called but fields already read from"
+ + " stream (by defaultReadObject or readFields)");
final ObjectStreamClass clazz = this.currentObjectStreamClass;
final byte[] prim_field_data = new byte[clazz.primFieldSize];
@@ -1036,7 +1077,7 @@
objs[i] = readObject ();
setBlockDataMode (oldmode);
-return new GetField ()
+prereadFields = new GetField ()
{
public ObjectStreamClass getObjectStreamClass ()
{
@@ -1046,7 +1087,31 @@
public boolean defaulted (String name)
throws IOException, IllegalArgumentException
{
- return clazz.getField (name) == null;
+ ObjectStreamField f = clazz.getField (name);
+
+ /* First if we have a serialized field use the descriptor */
+ if (f != null)
+ {
+ /* It is in serialPersistentFields but setClass tells us
+ * it should not be set. This value is defaulted.
+ */
+ if (f.isPersistent() && !f.isToSet())
+ return true;
+
+ return false;
+ }
+
+ /* This is not a serialized field. There should be
+ * a default value only if the field really exists.
+ */
+ try
+ {
+ return (clazz.forClass().getDeclaredField (