16

I need different classloaders to be able to unload classes. But i need to share objects between them (actually i am getting ClassCastException). So what are the solutions to deal with this?. Thanks

Wyvern666
  • 633
  • 1
  • 11
  • 26

4 Answers4

11

Objects from different classloaders can interact with each other through interfaces and classes loaded by a common classloader.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • i am getting your answer. But can i get the instance from an external object and save it to use directly? Or i need to use interfaces all the time to operate with other objects? – Wyvern666 Oct 01 '11 at 03:48
  • Andy is right on the mark. A common (parent) classloader defines the interface. Distinct classloaders load implementations of the interface (or common parent). Have your cake and eat it, too. – alphazero Oct 01 '11 at 05:38
  • @Wyvern666, you can directly use the instance whose class is defined through another classloader, but only through compile-time types defined through a parent classloader. – Andy Thomas Oct 01 '11 at 15:10
  • I load the plugins in similar way like the ServiceLoader API. Currently the plugins implements a common interface, so the main application invokes methods of the plugins. The parent loader of the plugins classloader is the default SystemClassLoader that loads the main application. So maybe i need another method in the interface to use betwen plugins or i need another interface?. Can you show me some little expample of this approach? – Wyvern666 Oct 01 '11 at 15:18
  • 1
    The two plug-ins sharing objects need references to the objects, and the objects need to implement a type that's loaded by a parent classloader. That could be done with the same interface used by the parent, or a different interface. The key point here is that the plugin classloaders delegate to their parents before loading their own copy of a class. So if you include the interface type in the classpath of the parent classloader, then both plugin classloaders should get the same class, via the parent classloader. – Andy Thomas Oct 02 '11 at 00:54
  • 1
    The one example that touches on this that I found in a quick googlesearch is from 1996, halfway down page 4: http://www.javaworld.com/javaworld/jw-10-1996/jw-10-indepth.html?page=4 . – Andy Thomas Oct 02 '11 at 00:55
  • @Andy Oh, now i understand. So i was near the right path. I have now an invoke() method to call methods from another plugins. The only problem is that when you want to truly share an object instance it must be loaded by te parent classloader of the childs classloaders like you say, so that makes more dificult the unloading process of the JVM. – Wyvern666 Oct 05 '11 at 15:29
2

Will also mention that if you are using interfaces, you can use java.lang.reflect.Proxy to create an instance of an interface local to your classloader which, under the hood, makes calls with reflection to the "real" (foreign) object from a different classloader. It's ugly, and if parameters or return types are not primitive, you will just be passing the ClassCastException further down the line. While you can rig something up to make this work, in general, it is better to either have a parent classloader with some shared types that you want to be able to use across classloaders, or use a more... serialized format for communication (slower), or only share interfaces that deal in primitives.

Ajax
  • 2,465
  • 23
  • 20
2

One of the primary objectives of using separate classloaders is to prevent exactly the kind of thing that you are trying to do. Security and name conflicts are good reasons for keeping this isolation. Here are a few ways that you can circumvent this isolation.

  1. Using the Common Class Loader

  2. Sharing Libraries Across a Cluster

  3. Packaging the Client JAR for One Application in Another Application

Refer to this link for more details.

RHT
  • 4,974
  • 3
  • 26
  • 32
  • mmm let see, i have a plugable aplication, so i have a classloader per plugin. Is a bad desicion to share data between this plugins? – Wyvern666 Oct 01 '11 at 03:54
  • Depends if the plugins can be trusted or not. – RHT Oct 01 '11 at 03:58
  • Yeah, in fact, the plugins have acces to the main application classes, but what i cant do is that plugins "see each other". – Wyvern666 Oct 01 '11 at 04:01
  • I know for Oracle Application Server, there is a parent child relationship between the applications so, multiple child applications can inherit libraries from the same parent. Weblogic uses templates to extend the domain. Try exploring something similar in your container. – RHT Oct 01 '11 at 05:15
0

In some situation it may be acceptable to 'switch the context' by for using a thread with desired classloader. For example you create SingleThreadPoolExecutor by a context you need and use that singleton instance to execute the code from different context.

Here was my situation: maven multi module web application deployed to tomcat. One web app registered error notification service bean, and DefaultUncaughtExceptionHandler for the whole JVM using the bean to deliver error by an email (with additional logic inside). When exception was thrown by web application which created the bean email was successfully sent, when exception was thrown by different web app, email functionality failed to cope with javax.mail classes (surprisingly not the exception itself). When I executed a method which send email in an executor, both cases start to work.

Mike
  • 20,010
  • 25
  • 97
  • 140