[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Serialization #6 (and final)
From: |
Guilhem Lavaux |
Subject: |
[PATCH] Serialization #6 (and final) |
Date: |
Sun, 07 Dec 2003 19:42:22 +0100 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 |
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 <address@hidden>
* java/io/ObjectInputStream.java:
(readFields): Changed implementation of GetField.
(readClassDescriptor): Documented.
Cheers,
Guilhem.
--- java/io/ObjectInputStream.java.orig 2003-12-04 19:36:56.000000000 +0100
+++ java/io/ObjectInputStream.java 2003-12-04 19:57:15.000000000 +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 address@hidden #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 (name) != null);
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new IllegalArgumentException (e.getMessage());
+ }
}
public boolean get (String name, boolean defvalue)
@@ -1188,24 +1253,73 @@
throws IllegalArgumentException
{
ObjectStreamField field = clazz.getField (name);
+ boolean illegal = false;
- if (field == null)
- return null;
-
- Class field_type = field.getType ();
+ try
+ {
+ try
+ {
+ Class field_type = field.getType();
+
+ if (type == field_type ||
+ (type == null && !field_type.isPrimitive()))
+ {
+ /* See defaulted */
+ return field;
+ }
+
+ illegal = true;
+ throw new IllegalArgumentException ("Field requested is of
type "
+ + field_type.getName ()
+ + ", but requested type
was "
+ + (type == null ?
+ "Object" :
type.getName ()));
+ }
+ catch (NullPointerException _)
+ {
+ /* Here we catch NullPointerException, because it may
+ only come from the call 'field.getType()'. If field
+ is null, we have to return null and classpath ethic
+ say we must try to avoid 'if (xxx == null)'.
+ */
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ return null;
+ }
+ finally
+ {
+ /* If this is an unassigned field we should return
+ * the default value.
+ */
+ if (!illegal && field != null && !field.isToSet() &&
field.isPersistent())
+ return null;
+
+ /* We do not want to modify transient fields. They should
+ * be left to 0.
+ */
+ try
+ {
+ Field f = clazz.forClass().getDeclaredField (name);
+ if (Modifier.isTransient(f.getModifiers()))
+ throw new IllegalArgumentException("no such field (non
transient) " + name);
+ if (field == null && f.getType() != type)
+ throw new IllegalArgumentException ("Invalid requested type
for field " + name);
+ }
+ catch (NoSuchFieldException e)
+ {
+ if (field == null)
+ throw new IllegalArgumentException (e.getMessage());
+ }
+
+ }
- if (type == field_type ||
- (type == null && ! field_type.isPrimitive ()))
- return field;
-
- throw new IllegalArgumentException ("Field requested is of type "
- + field_type.getName ()
- + ", but requested type was "
- + (type == null ?
- "Object" : type.getName ()));
- }
};
+ fieldsAlreadyRead = true;
+ return prereadFields;
}
/**
@@ -1977,6 +2091,7 @@
private boolean fieldsAlreadyRead;
private Vector validators;
private Hashtable classLookupTable;
+ private GetField prereadFields;
private static boolean dump;
- [PATCH] Serialization #6 (and final),
Guilhem Lavaux <=