classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Loader in ObjectStreamClass.readClassDescriptor


From: Nicolas Geoffray
Subject: Loader in ObjectStreamClass.readClassDescriptor
Date: Fri, 22 Jul 2005 15:41:53 +0200
User-agent: Mozilla Thunderbird 1.0.5 (X11/20050719)

Hello again,

There's something that, I think, misbehaves in readClassDescriptor.

Fields are read before the loading of the actual object's class CL in the stream, which is necessary. When loading the classes of the fields (before loading CL), the classloader given is the callersClassLoader which is set to currentLoader() the most recent user defined classloader on the execution stack.

When using the method with RMI here is the class context :
class java.io.VMObjectInputStream$1
class java.security.AccessController
class java.io.VMObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class java.io.ObjectInputStream
class gnu.java.rmi.server.RMIObjectInputStream
class gnu.java.rmi.server.UnicastServerRef
class gnu.java.rmi.server.UnicastServer
class gnu.java.rmi.server.UnicastServer
class gnu.java.rmi.server.UnicastConnection
class java.lang.Thread
class java.lang.VMThread

So the callersClassLoader is set to null and the fields of CL are loaded with the VM ClassLoader (which won't found any classes loaded by the application class loader or other user defined classloader)

Because RMI redefines the resolveClass(ObjectStreamClass), CL is found, as it used the "correct" classloader. The problem arrives when CL was loaded by MyClassLoader, and CL has one field whose class was also loaded by MyClassLoader.

What I suggest is to use the classloader of CL, once CL is loaded, to load the fields. What i do in the attached patch is reading the fields and storing them in a temporary class, loading CL as it was done before (this is when the RMI's resolveClass is used : gnu.java.rmi.server.RMIObjectInputStream) and finally loading the fields with CL's classloader.

Would that be a correct behaviour?

Cheers
Nicolas
*** java/io/ObjectInputStream.java      Fri Jul 15 15:57:35 2005
--- java/io/ObjectInputStream.java      Fri Jul 22 15:36:01 2005
***************
*** 468,473 ****
--- 468,484 ----
        }
    }
  
+ 
+   private class TemporaryStreamField{
+     String field_name;
+     String class_name;
+ 
+     TemporaryStreamField(String field, String clazz){
+       field_name = field;
+       class_name = clazz;
+     }
+   }
+ 
    /**
     * This method reads a class descriptor from the real input stream
     * and use these data to create a new instance of ObjectStreamClass.
***************
*** 497,509 ****
      short field_count = this.realInputStream.readShort();
      if(dump) dumpElementln(Short.toString(field_count));
      ObjectStreamField[] fields = new ObjectStreamField[field_count];
      ObjectStreamClass osc = new ObjectStreamClass(name, uid,
                                                  flags, fields);
      assignNewHandle(osc);
  
-     if (callersClassLoader == null)
-       callersClassLoader = currentLoader();
-             
      for (int i = 0; i < field_count; i++)
        {
        if(dump) dumpElement("  TYPE CODE=");
--- 508,518 ----
      short field_count = this.realInputStream.readShort();
      if(dump) dumpElementln(Short.toString(field_count));
      ObjectStreamField[] fields = new ObjectStreamField[field_count];
+     TemporaryStreamField[] temp_fields = new 
TemporaryStreamField[field_count];
      ObjectStreamClass osc = new ObjectStreamClass(name, uid,
                                                  flags, fields);
      assignNewHandle(osc);
  
      for (int i = 0; i < field_count; i++)
        {
        if(dump) dumpElement("  TYPE CODE=");
***************
*** 521,529 ****
          class_name = (String)readObject();
        else
          class_name = String.valueOf(type_code);
!                 
!       fields[i] =
!         new ObjectStreamField(field_name, class_name, callersClassLoader);
        }
              
      /* Now that fields have been read we may resolve the class
--- 530,537 ----
          class_name = (String)readObject();
        else
          class_name = String.valueOf(type_code);
!       
!       temp_fields[i] = new TemporaryStreamField(field_name, class_name);
        }
              
      /* Now that fields have been read we may resolve the class
***************
*** 558,563 ****
--- 566,577 ----
          throw cnfe;
        }
  
+     ClassLoader loader = clazz.getClassLoader();
+     for(int i =0; i < field_count; i++)
+       fields[i] = new ObjectStreamField(temp_fields[i].field_name,
+             temp_fields[i].class_name, loader);
+ 
+ 
      boolean oldmode = setBlockDataMode(true);
      osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
      classLookupTable.put(clazz, osc);

reply via email to

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