5 Replies Latest reply: Feb 15, 2010 8:05 AM by 791266 RSS

    ObjectInputStream and Class Loading

    843790
      Hello,

      I have a serializable object that I have to pass as an argument to a session bean. It therefore is serialised/deserialised with a default object inputstream, which uses the bootstrap class loader as default. However, the object contains objects of which the classes cannot be loaded by the bootstrap class loader, in fact the class definitions are in a .jar file. I thus would need to be able to deserialise these objects with a custom class loader at the receiver's end. The receiver has the .jar file and the object that is to be deserialised is a trusted object.

      I could manually control the deserialization of the object by defining the following method:
      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
         ...
      }
      I could also deserialize objects from a self created ObjectInputStream with a class loader of choice with the following class:
      public class CustomObjectInputStream extends ObjectInputStream {
          private ClassLoader classLoader;
          
          public CustomObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
              super(in);
              this.classLoader = classLoader;
          }
          
          protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
              return Class.forName(desc.getName(), false, classLoader);
          }
      }
      However I have no control over the type of ObjectInputstream passed as argument to the readObject method, which uses the bootstrap class loader.

      I give 5 duke stars to who can explain me a working solution.
        • 1. Re: ObjectInputStream and Class Loading
          EJP
          object inputstream, which uses the bootstrap class loader as default
          No it doesn't. ObjectInputStream uses something called latestUserDefinedLoader() to define new classes with, which at the worst would be the bootstrap class loader. Not sure exactly what latestUserDefinedLoader() actually means, as it's buried in the JVM code, but you could try Thread.currentThread().setContextClassLoader() inside readObject() before you call defaultReadObject().
          • 2. Re: ObjectInputStream and Class Loading
            843790
            Thanks for the suggestion, but it doesn't work. Thread.currentThread().setContextClassLoader() appears to have no effect whatsoever on the class loader. Your suggestion about latestUserDefinedLoader() made me realise though that the situation is serious. This is a native method and it appears to be conceptually impossible to crack the standard ObjectInputStream for it to use the class loader of your choice. I filed a bug request for this.

            However, after a bit of thought I found a work around: if you can't control the way the EJB container serializes and deserializes objects, then serialize the objects before the EJB serializes them, pass the arguments as byte arrays and deserialize them only after the EJB container has deserialized them as byte arrays.

            You didn't give me the solution, but you made me realise that it wouldn't make sense to look for a conventional solution anymore, as there wouldn't be one so I give you one duke star. Thanks for the suggestion!
            • 3. Re: ObjectInputStream and Class Loading
              EJP
              Have a look at java.rmi.MarshalledObject, might be a way to do what you want.
              • 4. Re: ObjectInputStream and Class Loading
                843790
                I was searching in the forum, as I had the same problem.

                Here is my solution, which seems to be much nicer:
                public class ClassLoaderObjectInputStream extends ObjectInputStream{
                
                     private ClassLoader classLoader;
                
                     public ClassLoaderObjectInputStream(ClassLoader classLoader, InputStream in) throws IOException {
                          super(in);
                          this.classLoader = classLoader;
                     }
                     
                     @Override
                     protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException{
                     
                          try{
                               String name = desc.getName();
                               return Class.forName(name, false, classLoader);
                          }
                          catch(ClassNotFoundException e){
                               return super.resolveClass(desc);
                          }
                     }
                }
                • 5. Re: ObjectInputStream and Class Loading
                  791266
                  >

                  Hi,

                  Please, don't resurrect old threads. I'm locking this one.

                  Kaj