Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast two instance of the same loaded different classloader?

I have two different webapps, and each load the same class A with different classloader. When I put one instance in the session and then get it from the other webapp, a ClassCastException is thrown.

For example, in webapp A, I store a in the session, then in webapp B, I get the a from the session and cast it to A, the ClassCastException is thrown.

Is there a way to resolve this?

like image 821
xiaolg2008 Avatar asked May 13 '12 07:05

xiaolg2008


People also ask

Can we load the same class by two ClassLoader?

A class is always identified using its fully qualified name (package. classname). So when a class is loaded into JVM, you have an entry as (package, classname, classloader). Therefore the same class can be loaded twice by two different ClassLoader instances.

Can you have more than one ClassLoader in Java?

There can be multiple classloaders in a normal Java program. The one that loads your main class, ClassLoader , is the default one, and from your code, you can create and use as many classloaders as you like.

How many JVM Classloaders are there?

When the JVM is started, three class loaders are used: Bootstrap class loader. Extensions class loader. System class loader.

What are different types of ClassLoader?

As we can see, there are three different class loaders here: application, extension, and bootstrap (displayed as null). The application class loader loads the class where the example method is contained. An application or system class loader loads our own files in the classpath.


2 Answers

Is there a way to resolve this?

Basically no.

As far as the JLS is concerned, the types are different types, and there is no way that the JVM will allow you to pretend otherwise. For instance, the classes could have different code and different object layouts. If you could trick the JVM into treating the types as the same, you would be able to blow away JVM runtime safety. That way lies insanity.

The solution is to make sure that you don't have two different class loaders loading the same class. In the context of Tomcat, this means that if two or more webapps need to share instances of a class, then that class must be defined in a classloader that is common to both; e.g. put the JAR file in the $CATALINA_HOME/lib or $CATALINA_HOME/common directory.


If there is a technical reason why the classes have to be loaded by different classloaders (maybe because the classes really are different), then you could work around the problem by defining an interface that both versions of the class implement, and then programming to the interface rather than the implementation class. Of course, the interface needs to be loaded by a shared classloader ... or else you run into the same problem again.

like image 103
Stephen C Avatar answered Nov 15 '22 19:11

Stephen C


You should avoid this situation, basically - either put both bits of functionality in the same webapp, or move the library containing class A into an appropriate location such that only one classloader will be used. Two classes loaded by different classloaders are entirely distinct in the JVM - you simply won't be able to cast between them.

See the Tomcat classloader documentation for more details about the various classloaders used. It looks like you'd want to put this common class into the common classloader area. As the documentation notes, this is pretty unusual, but if you really want to share an object between two webapps (which is also unusual) it's probably the easiest way forward.

like image 45
Jon Skeet Avatar answered Nov 15 '22 20:11

Jon Skeet