classpath
[Top][All Lists]
Advanced

[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;
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]