Can I run code before servlet class loading on Tomcat? - java

I'm doing some runtime bytecode manipulation on some of my business objects, and it's very important that they be loaded in the right order. Currently I'm simply calling Class.getSimpleName() on them in the right order in my Startup servlet. This has been working just fine, but if there's a better way, I'm all ears.
Now, however, I need a method in one of my servlet filters to return a concrete business object type. This is causing the classloader to load that particular business object class first (out of order) and things break.
What I'd like is to be able to run my getSimpleName() hack before any of my servlets or filters are loaded. Is there some place I can put code that runs before the classloader even loads my filters?

Yes, you can.
Look at ServletContextListener.

The tomcat class loader works in this fashion.
if you want to load any classes before any of you web-app classes load, then you can put those classes in a jar file and deploy it to tomcat common library, these classes will be loaded before your web application classes are loaded by the class loader.
You can check the documentation of how apache tomcat class loader works here

Related

class MyClass cannot be cast to class MyClass (MyClass is in unnamed module of loader org.glassfish.[...].WebappClassLoader#1)

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.

Java ClassLoader to deal with "Instance" classes

As we know java class loading works like in picture below.
When we have a notion of plugin in our application (like app servers) we sometimes need some classes to be loaded in the instances class loader rather than in parent, so that each new instance (plugin, webapp or whatever) loads that particular class not delegating the parent...
For example Log4j classes, we need them to be loaded for each instance.
So in order to do this the best approach that came into my mind is to write custom classloader that will take a list of class names which shall be prevented from being delegated to parent classloader (ideally we want instances to be in complete isolation).
So the the application that will load other "instances" will use that custom classloader while loading those "instances"...
Is there an implementation of such classloader that solves this issue? (given that we dont want to know what OSGi is and we work with pure java no frameworks etc...)
My searches end up pointing some frameworks or some web container specific solutions, yet this is quite a simple task that is solved with one class, I'd like to find out if i'm missing something before i start implementing it.
Update (digging deeper) : suppose there is a class loaded by bootstrap which has static state that can be shared between instances (and we really badly want to make sure instances are completely isolated), now that class is obviously not included in our classpath, but it is loaded, and if we copy it instead of reffering it we will achieve the required isolation.
So do we have the notion of copying or cloneing a class from one classloader to other?

Tricky Classpath issue

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

Application wide custom ClassLoader

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. :)

Concurrent access causes ClassCastException (X cannot be cast to X), or how to resolve such class loading problems in JBoss

I have a problem concerning JBoss and class loading.
Here is the configuration I am working with. I have two instances of JBoss 4.2.3.GA on the same server. On each instance an application is running, and these applications are communicating with each other. There is an utility class, packed in both applications archives. This utility class is strictly the same in both applications.
This usually works fine, but in particular situations, I get ClassCastException. The case is the following:
A user is using a web application, which calls the application on the first JBoss instance (let's call it the application A). And application A calls the application B (on the second instance). This particular call takes several seconds to succeed.
If another user is trying to use the web application in a similar context (call to application A, which calls application B), and if this call happens during the first user call, I get systematically a ClassCastException : X cannot be cast to X (where X is my utility class, shared by both applications).
I found some information, and I deduced it was a class loading problem. Indeed, in this particular context of concurrent calls, my utility class is not loaded by the same class loader. I put a print command to see which class loader is used. In usual behavior, org.jboss.mx.loading.UnifiedClassLoader3 is used to load classes. In the particular described above, the application B seems to used a different class loader for the second user. My print command gave me the following:
WebappClassLoader
delegate: false
repositories:
/WEB-INF/classes/----------> Parent Classloader:java.net.FactoryURLClassLoader#de8209
My guess is that application B return an instance of my utility class loaded by this WebappClassLoader, and application A (which is using UnifiedClassLoader3) cannot cast it.
But i don't get why the UnifiedClassLoader3 cannot be used in this case, on application B. And why is this WebappClassLoader used ?
All I know about the class loading configuration in my JBoss instances is that class loading isolation is used, the following configuration is used for both applications :
<jboss-app>
<module-order>strict</module-order>
<loader-repository>applicationAorApplicationB.ear</loader-repository>
</jboss-app>
Do you have any advice to resolve this problem? How can I configure jboss class loader to avoid these class cast exception?
I precise that there is no hot deployment: I clean the server each time I deploy the applications.
If JBoss is using different classloaders for different packages, it is actually following the behavior according to the spec. For many releases it did not do this. You can disable WAR classloader isolation. See the JBoss documentation for more information.
You can also use a variety of different methods that do not require the applications to be in the same classloader for communication, and this would make your applications more specification compliant. See this stackoverflow question for more details.

Categories

Resources