I have two portal web project
project1
project2
I have a shared library(sharedLibrary.jar) set which is used in both the above project. My shared library is used to lookup dyna cache and set/get data from it.
I am setting a my own bean bean(say it is com.test.UserBean) to dyna cache from project 1.
Now from project 2 am trying to retrieve the bean(com.test.UserBean) from cache. When doing so i am getting classCastException.
but when I assign it like below it was showing me the that the object is com.test.UserBean
Object obj=distributedMap.get();
My bean implements Serializable interface and has a serialVersionUID field.
I am not sure what happening here. Is it a class loader issue/something else.
Can any one shed some more light on this ?
This is less likely a serialization issue and more likely a classloader issue.
If the class was truly loaded by both portlet web applications by a single, common class loader then instances can be shared via DynaCache.
If however two different classloaders are used to load the same .class from the same .jar (on disk) and the two applications share a single instance (e.g. via DynaCache distributed map) you will encounter a ClassCastException - even though, as you've seen, myInstance.getClass().getName() yields the same string.
To confirm this you can enable a service and use the WebSphere classloader viewer. This will let you, per module, troubleshoot your "two classloaders, one class" issue. There is a companion doc on the InfoCenter doc which walks you through the troubleshooting process. The classloader viewer will show you which .jar and which classloader was used to load the com.test.UserBean in each module. For example, you may have accidentally packaged the jar in WEB-INF/lib of one and not the other and have parent-last classloading enabled.
Related
Why this error sometimes in deploy phase appens in Glassfish / Payara application server?
I can guess that the application server is trying to use two different classes of two different classloaders but is there a way to prevent it to do this behavior?
I tried to lookup some source online whitout finding nothing.
Edit : this happens on the same application in time of redeploy. It gets solved by a restart of the application server but obliviously this is not a solution
java.lang.ClassCastException: class com.MyClass cannot be cast to class com.MyClass (com.MyClass is in unnamed module of loader org.glassfish.web.loader.WebappClassLoader#1, com.MyClass is in unnamed module of loader org.glassfish.web.loader.WebappClassLoader#2)
Last Edit, after the great response of Stephen C.
What are the tools to undestand why Payara/GC doesn't destroy the old object?
I can guess that the application server is trying to use two different classes of two different classloaders but is there a way to prevent it to do this behavior?
Yes, that's what I think is happening. If identical .class files are loaded by different classloaders, the resulting runtime types are different and cannot by cast.
There are three ways to avoid this:
Don't pass or share these objects between different webapps.
Move the JARs that define the classes that need to be shared into the web container's shared library area ... so that they are loaded by the webcontainer's classloader rather than the webapp classloader(s).
If the classes need to be loaded by multiple webapp classloaders (e.g. because the have the same name but different implementations) you may need to rearchitect your application so that the classes implement a common interface that is loaded by a single classloader. If your webapp code then only casts to the shared interface, you won't run into this problem.
What if the web app is the same? (so when the application redeploy the same app)
If that is the case, then it sounds like the problem is that your webapp's shutdown code is not doing the right thing. Java objects created by the earlier deployment of the webapp are leaking into the later one.
Check that something is not caching application objects.
Check that application objects are not hiding in session state or thread-locals, or something like that.
Working on an existing application, it runs on Weblogic as a massive ear file.
There is custom code, written by my organization, as well as code written by the vendor that all runs on one classpath when weblogic starts up.
Some of our custom code uses spring 1.2, in the latest version of the vendors code, they use spring3. So we cannot get the ear to completely work unless we can get each component the spring version it needs in order to function. But since they are both using the classpath that weblogic is started on, either spring1.2 or spring 3.0 will be first depending on the order in the classpath.
Am I stuck? Missing something? I've never had to deal with classpaths at this level.
Thanks
Classloaders use a delegation model when loading a class. The classloader implementation first checks its cache to see if the requested class has already been loaded. This class verification improves performance in that its cached memory copy is used instead of repeated loading of a class from disk. If the class is not found in its cache, the current classloader asks its parent for the class. Only if the parent cannot load the class does the classloader attempt to load the class. If a class exists in both the parent and child classloaders, the parent version is loaded. This delegation model is followed to avoid multiple copies of the same form being loaded. Multiple copies of the same class can lead to a ClassCastException.
Think setting the following in weblogic.xml might help
prefer-web-inf-classes Element
The weblogic.xml Web application deployment descriptor contains a prefer-web-inf-classes element (a sub-element of the element). By default, this element is set to False. Setting this element to True subverts the classloader delegation model so that class definitions from the Web application are loaded in preference to class definitions in higher-level classloaders. This allows a Web application to use its own version of a third-party class, which might also be part of WebLogic Server. See "weblogic.xml Deployment Descriptor Elements".*
When using this feature, you must be careful not to mix instances created from the Web application's class definition with issuances created from the server's definition. If such instances are mixed, a ClassCastException results.
Refer to the URL below
Oracle Weblogic Server
I have a custom URLClassLoader which loads a couple of classes from jar files outside the normal classpath. So far, so good.
My problem is that I can't call this ClassLoader each and every time when I need a class loaded by my ClassLoader because these classes might by used by third party libs. For that reason I added the classes to the current Thread ClassLoader by reflection:
ProtectionDomain pd = getClass().getProtectionDomain();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final java.lang.reflect.Method clM = ClassLoader.class.getDeclaredMethod("defineClass", Class.class);
clM.invoke(classLoader, className, byteContent, 0, byteContent.length, pd);
But when it comes to a call to findClass inside that Thread ClassLoader and the requested class has not been added by me yet, I get a NoClassDefFoundException. Of course.
My question is now, is there a way to put my ClassLoader in the global class loading chain of my application? Using the Java option for system ClassLoader is not possible as my ClassLoader can be contained in a web application and deployed as a war file. I also tried using Thread.currentThread().setContextClassLoader() but once a new Thread is created, it of course doesn't have my ClassLoader set.
I searched the web for days but couldn't find any solution.
Thanks for your help and any suggestions.
Best regards,
Gerry
Not really, especially if you want this to be compatible with running as a web application.
You've got multiple problems to solve here. Web containers are permitted to run you under a security manager that will make your code not work (i.e., they can forbid access to the filesystem and/or forbid the creation of ClassLoaders). Java was designed to allow the safe loading of mobile code (it was originally targeting, of all things, cable set-top boxes), and so you can imagine the ability for an application to modify the system class loader on the fly was not part of the architecture.
For the application, what you ought to be doing is either (1) putting your JAR files from which you're specially loading these classes in the system classpath, or (2) loading your application in a custom class loader, then having that custom class loader load your classes (in essentially the same way you are now). Load the third-party libraries in the same class loader. Now you're going to be OK, regardless of what you mean by "might be used by third-party libraries" (this was confusing to me and I am not sure what technique they might be using, and it matters).
For the webapp, you should bundle the needed classes in the web application. You're defeating the web application design by attempting to load classes from elsewhere; the idea of the web application and .war is to make these things self-contained.
So you're doing this the wrong way. If you insist on doing it the wrong way, there may be various non-portable hacks you can start using in order to get your code working properly in particular situations, but I'm only going to write one answer for now and see what you think. :)
If I have two webapps, both of which have the same third party library jars in their web-inf/lib directories, say log4j.....when the first webapp is loaded and a log4j class is created, this class is loaded into the heap. When the second webapp is loaded and tries to load a log4j class, will it find the class in the heap and use that one? Or will it load its own copy of the class into the heap?
Hmm I think it is mostly a ClassLoader problem here, it still depend of the application server you are using, but I guess most of them use a single JVM and reserve a ClassLoader per running webapp so that you can have different webapp with different version of the same jar/clases running alltogether.
In tomcat for instance, if you need to have some shared libraries, you can use the /tomcat/shared/lib folder where you put all the jars that will be accessible by all your webapps.
Otherwise yes, different webapp won't share the same heap, it would mean webapp could access object created by other webapp running in the same application server
No, it shouldn't.
The fact classes are loaded on the heap mean nothing here. as each class loader maintains its own list of classes it loaded.
However, Classloaders are also organised into a tree and they are supposed to ask their parent classloaders to attempt to load the class first, as described in the javadoc of the ClassLoader class.
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
However, webservers typically don't follow this delegation model, to avoid libraries used by the webserver itself being picked up by webapps. (This behaviour is sometimes configurable, but it depends on the webserver you're using.)
So in practice every webapp should have its own separate class space, independent of all the other webapps, therefore they can even use two different versions of the same library without any problems.
The other important lesson is that the same class file loaded by two different class loader will actually be two separate classes in the heap and objects from one class will not be compatible with the other class.
I have multiple web-apps running on an app server and each web-app WAR file contains a copy of the same jar file.
Does this mean that a class in that jar file will be loaded multiple times in the JVM, once for each WAR file it exists in? Following on from that, if I have a static synchronized method in such a class, is it only synchronized among threads within the web-app it exists in but not synchronized against the same method in the same class in a different jar file in a different WAR file? (Hope the question makes sense, will clarify if necessary).
If this is the case I presume the best solution is to remove the jar file from each WAR file and deploy it to a shared classpath folder on the server?
A Java classloader typically works by looking for classes in one or more places in a fixed sequence. For instance, the classloader that loads your application when you run it from the command line looks first in the rt.jar file (and others on the bootclasspath), and then in the directories and JAR files specified by your classpath.
A webapp classloading is similar in principle, but a bit more complicated in practice. For a particular webapp, a webapp's classloader looks for classes in the following order. For example Tomcat 6 looks for classes in this order:
Bootstrap classes of your JVM
System class loader classes (described here)
/WEB-INF/classes of the webapp
/WEB-INF/lib/*.jar of the webapp
$CATALINA_HOME/lib
$CATALINA_HOME/lib/*.jar
Of course, once the classloader has found the class it is looking for, it looks no further. So classes with the same name later in the order won't get loaded.
The complication is that the web container has one classloader for each webapp, and these classloaders delegate to other classloaders that manage the common classes. In practice, this means that some classes will only ever be loaded once for the entire container (e.g. 1. and 2.) and others may get loaded multiple times by different classloaders.
(When a class is loaded more than once, it results in distinct Class objects and distinct class statics. The versions of the class are different types as far as the JVM is concerned and you cannot typecast from one version to the other.)
Finally, Tomcat can be configure to allow individual webapps to be "hot loaded". This entails stopping a webapp, creating a new classloader for it, and restarting it.
FOLLOWUP
So ... synchronizing a static method will not protect access to a shared resource where the class has been loaded multiple times?
It depends on the details, but it probably won't. (Or to look at if another way, if a class has actually been loaded multiple times, then a static method of each "load" of the class will access a different set of static fields.)
If you really want a singleton application class instance to be shared by multiple webapps in the same container, it is simplest if you put the class into $CATALINA_HOME/lib or the equivalent. But you also should ask yourself if this is good system design. Consider combining the webapps, or to using request forwarding etc instead of a shared data structure. The singleton pattern tends to be troublesome in webapps, and this flavor is even more so.
Java EE application servers typically use multiple classloaders to isolate applications from each other, and allow new versions of one application to be deployed without affecting other apps.
You get patterns such as several WAR files and one EJB file in an EAR with a hierarchy of classloaders, each WAR having it's own.
This does lead to duplication as you describe, but this is not necesserily a bad thing. It means that you can even have different versions of the same JARs deployed a the same time, and that may actually be benficial, allowing incremental migration to new versions.
Some application servers (WebSphere for exmaple) have explicit support for a shared library concept, and I do use that.
Be wary of just popping JARs into arbitrary classpaths, you run the risk of destabilising the app server itself.
Most application server use most specific along a path takes precedence policy.
If you have multiple library that do the same thing, You should consider to put them inside application server lib (f.e: TOMCAT_HOME/lib)