ObjectInputStream and Class Loading

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:

privatevoid 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:

publicclass CustomObjectInputStreamextends 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.

[2241 byte] By [toon_macharisa] at [2007-11-27 1:56:07]
# 1

> 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().

ejpa at 2007-7-12 1:30:03 > top of Java-index,Core,Core APIs...
# 2

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!

toon_macharisa at 2007-7-12 1:30:03 > top of Java-index,Core,Core APIs...
# 3
Have a look at java.rmi.MarshalledObject, might be a way to do what you want.
ejpa at 2007-7-12 1:30:03 > top of Java-index,Core,Core APIs...