Copy an Object from one ClassLoader to Another??

J

John Davison

I have an Object that was created in a custom class loader. Since a
Class is defined as the class name plus the class loader, a Class from
one ClassLoader is not equivalent to a Class from another ClassLoader.
For example:

Class c1 = getClass().getClassLoader().loadClass( "com.acme.FooBar" );
Class c2 = CustomClassLoader.loadClass( "com.acme.FooBar" );
FooBar newC2 = (FooBar)c2; // This throws ClassCastException!

You can not cast c2 to FooBar because the FooBar class loaded by the
system ClassLoader is not equivalent to the FooBar class that created
c2.

I've worked around this problem by serializing my c2 object into a
byte array, then deserializing my byte array back into an Object.
This has the effect of recreating the c2 object in system class
loader.

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( baos );
oos.writeObject( c2 );

ByteArrayInputStream bais = new ByteArrayInputStream(
baos.toByteArray() );
ObjectInputStream ois = new ObjectInputStream( bais );
FooBar newC2 = (FooBar) ois.readObject();

It's a bit of a hack, but it works. The only caveat is that FooBar
must be Serializable. Now, how do I get the object created by
CustomClassLoader into my system class loader??? I've found one
method, but I'm looking for other suggestions (hopefully better than
mine).

-- John
 
W

Will Hartung

John Davison said:
I have an Object that was created in a custom class loader. Since a
Class is defined as the class name plus the class loader, a Class from
one ClassLoader is not equivalent to a Class from another ClassLoader.
For example:

Class c1 = getClass().getClassLoader().loadClass( "com.acme.FooBar" );
Class c2 = CustomClassLoader.loadClass( "com.acme.FooBar" );
FooBar newC2 = (FooBar)c2; // This throws ClassCastException!

You can not cast c2 to FooBar because the FooBar class loaded by the
system ClassLoader is not equivalent to the FooBar class that created
c2.

I've worked around this problem by serializing my c2 object into a
byte array, then deserializing my byte array back into an Object.
This has the effect of recreating the c2 object in system class
loader.

This is kind of a "Doc it hurts when..." thing.

Why are you loading the same class from two different class loaders? As you
can see, that simply spells trouble.

One thing you may try is to not work with classes here but rather
interfaces. Stuff the interface into the area where only the system class
loader can see it, and then simply refer to the interface.

Class c1 = getClass().getClassLoader().loadClass( "com.acme.FooBar" );
Class c2 = CustomClassLoader.loadClass( "com.acme.FooBar" );

Object c1Instance = c1.newInstance();
Object c2Instance = c2.newInstance();


FooBarInterface newC1 = (FooBarInterface)c1Instance;
FooBarInterface newC2 = (FooBarInterface)c2Instance;

Regards,

Will Hartung
([email protected])
 
D

David Hilsee

John Davison said:
I have an Object that was created in a custom class loader. Since a
Class is defined as the class name plus the class loader, a Class from
one ClassLoader is not equivalent to a Class from another ClassLoader.
For example:

Class c1 = getClass().getClassLoader().loadClass( "com.acme.FooBar" );
Class c2 = CustomClassLoader.loadClass( "com.acme.FooBar" );
FooBar newC2 = (FooBar)c2; // This throws ClassCastException!

You can not cast c2 to FooBar because the FooBar class loaded by the
system ClassLoader is not equivalent to the FooBar class that created
c2.

I think you left a call to newInstance() out. You cannot cast c2 to newC2
because c2 is an instance of Class and FooBar is not derived from it. I
just wanted to make sure that nobody gets confused.
 
J

John Davison

Will Hartung said:
This is kind of a "Doc it hurts when..." thing.

Why are you loading the same class from two different class loaders? As you
can see, that simply spells trouble.

One thing you may try is to not work with classes here but rather
interfaces. Stuff the interface into the area where only the system class
loader can see it, and then simply refer to the interface.

Class c1 = getClass().getClassLoader().loadClass( "com.acme.FooBar" );
Class c2 = CustomClassLoader.loadClass( "com.acme.FooBar" );

Object c1Instance = c1.newInstance();
Object c2Instance = c2.newInstance();


FooBarInterface newC1 = (FooBarInterface)c1Instance;
FooBarInterface newC2 = (FooBarInterface)c2Instance;

I thought about using interfaces, unfortunately I don't have control
over the classes that are being created. :(

-- John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top