Search code examples
javaweblogicclassloaderoracle-adfear

ClassCastException when loading same Class from two different wars in same ear, due to different class loaders


I am working on an existing ADF application where there are two different project modules inside an EAR deployed on weblogic.
1. Model Project with VOs, EOs and AM (Contains Application Module Implementation)
2. UI Project (war is created for this project using build files of Model Project)

I have added another war file for enabling rest services along with UI. Reason for different war is that UI war requires web authentication and we want to by-pass that in Rest war by providing multi-token authentication. So now we have two wars and three modules.
1. Model Project
2. UI Project
3. Rest Project (Uses build files from UI project and Model Project)

Now the problem is the Application Module Implementation is retrieved using

ApplicationModuleHandle amHandle = Configuration.createRootApplicationModuleHandle("**.**.classpackage","config_name");

amImpl = (MyAMImpl) amHandle.useApplicationModule();

And if one of the wars creates an object of my MyAMImpl the other gets a

ClassCastException.

My query is if there is any way to load both wars with same class loader using weblogic-application.xml. Or any other configuration at code level.

P.S. : I am avoiding to mess up my code with custom class loaders or forcing same class loader inside the application code since it is an existing application.

Any help is highly appreciated.

EDIT: First there is another module which contains a singleton object. Which is for further clarity is a Quartz Singleton. And the UI project contains a Trigger Listener which invokes the Application Module.

So I with a lot of troubleshooting I found the reason and a solution for this.

Reason : Both wars use separate class loaders and would create different instances of Quartz Singleton. Each would have there own instances of TriggerListener as well.
So when one of the modules invoke QuartzScheduler and Trigger Listener, it creates an Application Module (which is persisted in application and is not released).
Now when the second application invokes QuartzSingleton new instance of same and Trigger Listener are created for the second class loader but same instance of Application Module is being returned. Since the second class loader has no clue of the Application Module returned it throws a ClassCastException.

Solution : Add the project containing Quartz Scheduler at EAR level and add build output of the project in war projects (so they do not throw compile time exceptions). This would enable the entire application to have a single instance of Quartz Scheduler Singleton using Class Loader of the application which is in fact the parent class loader for the two wars. Which enables both wars to be able to find the Class in parent class loader and the exception is not thrown, since now the all the three instances ie, Quartz Scheduler Singleton, TriggerListener and Application Module reside in same class loader.

P.S. : I know it was not much explained query at beginning, because I myself was not sure of the reason. Sincere apologies for that. And the application had definite design flaws. It still has though. Hope someone finds this useful


Solution

  • I have added the reason and solution at the query as well.

    Reason : Both wars use separate class loaders and would create different instances of Quartz Singleton. Each would have there own instances of TriggerListener as well. So when one of the modules invoke QuartzScheduler and Trigger Listener, it creates an Application Module (which is persisted in application and is not released). Now when the second application invokes QuartzSingleton new instance of same and Trigger Listener are created for the second class loader but same instance of Application Module is being returned. Since the second class loader has no clue of the Application Module returned it throws a ClassCastException.

    Solution : Add the project containing Quartz Scheduler at EAR level and add build output of the project in war projects (so they do not throw compile time exceptions). This would enable the entire application to have a single instance of Quartz Scheduler Singleton using Class Loader of the application which is in fact the parent class loader for the two wars. Which enables both wars to be able to find the Class in parent class loader and the exception is not thrown, since now the all the three instances ie, Quartz Scheduler Singleton, TriggerListener and Application Module reside in same class loader.