It is possible to have 2 jars with the same name of class. Does it possible control which class will be loaded(used) by JVM ?
Thanks.
If you have two jar with the same class, which one will be loaded depends on the order of the jars. You can also create your own class loader, and chain it to the parent class loader. Therefore your class loader will try to load the class, and if it fails, it will fall back to parent. Take a look at this one for example: http://download.oracle.com/javase/1.4.2/docs/api/java/net/URLClassLoader.html
It is possible and it will simply load the one that appears first on the classpath.
Related
My situation is as follows:
I have two scala applications, app 1 and app 2. Both use sbt. I ran "publishLocal" in the sbt shell for App 2, and then made App 2 a library in app 1 (I added it as a library dependency in build.sbt). Within app 2, I have a function, foo, the line
Class.forName(<CLASS NAME>)
I want to pass a class path for class bar from app 1 to the foo function in app 2, so that I can get use an instance of the bar class in the foo function. However, when I try this, I get a ClassNotFoundException. I have isolated this problem to the fact that the code which calls "Class.forName" is using the bootstrap class loader, and the bar class is loaded using some other class loader. I cannot change the code in app 2, but I can change the code in app 1 - is there a way that I can somehow specify that bar should be loaded with the bootstrap class loader, or in some other way make it discoverable for app 2 in the foo function?
If I understood correctly, you have a setup like:
app1 (= Application)
Bar.class
app2 (= Lib)
class with function foo(...) that wants to use Bar.class
where they both were loaded by different classloaders and you want to lookup Bar.class inside the foo function in app2.
Does the app2 setup have any classpath dependencies on app1 so that classes of app1 are actually loadable by app2? If not then chances are low that you are able to use that class.
Let's recap what is happening here. Classloaders usually work on a delegation model. Classloaders respecting the delegation model will first check their loacal cache whether the class was already loaded by that classloader before and if not ask their parents whether they know the definition of that class. Only if none of the ancestors knew about that class before the actual bytes defining the class are loaded by the class loader that initiated the lookup chain. In order to load the bytes of that class definition, the classloader will usually check its classpath if there is any JAR archive or directory mentioned that contains the definition. If multiple sources are present that provide the class definition, the first one found will be loaded which could lead to shadowing issues down the road if multiple versions of the same class linger around in different archives/directories.
So, if the classpaths of these two applications (or application and library) are setup in a way that they don't have access to the other's Java archive (JAR) they won't be able to even load and lookup the class definitions of the other application. Probably the best advice to give is to extract common classes into an own library, i.e. commons or base, and add this library to the classpath of both applications so that the application loader of the respective application/library is able to load the class definitions of shared classes.
Note however, the same class definition, i.e. for class Bar, loaded by two different classloaders will result in CL1.Bar != CL2.Bar as the classloader who loaded that class definition is a part of that class, meaning that event though the byte representation of the class in both classloaders is identical, the actual Class<Bar> object you obtain is different. This quickly may get an issue if you think about returning the class definition loaded in foo(...) and compare it in app1 with some local Bar.class and wonder why a check of barObject.getClass() instanceof Bar (or the like) is failing, assuming barObject is the product returned by app2.foo() and Bar being app1.Bar.class.
In regards to Class.forName(...) using the bootstrap classloader: Class has actually two forName(...) methods present. One only taking the fully qualified class name to return the class object for, which uses the classloader that actually loaded that respective class, which is almost always the boostrap classloader. The second one has the following signature:
Class<?> forName(String className, boolean initialize, Classloader loader) where you can specify the classloader it should use to lookup and load the class definition with. So, as long as you at least have a reference to a class loaded by the other class loader present you can obtain the reference to that classloader via otherAppObject.getClass().getClassLoader().
Further note that if your applications use Java's module capabilities, you might need to open up the modules so that classloaders are actually able to load the definitions for these classes at all.
... is there a way that I can somehow specify that bar should be loaded with the bootstrap class loader, or in some other way make it discoverable for app 2 in the foo function?
I don't know about sbt TBH, but usually adding the location of the JAR archive of app1 to the classpath of app2 should be enough to allow the classloader of app2 to load, define and return the class definition of classes used in app1. As mentioned, extracting common classes used by both to a library that is added to both applications classpath is probably the recommended way.
I have class Foo which needs class Bar as an import. Class Bar is loaded with different class loader than Foo and while defining Foo, class loader can't find Bar and throws ClassNotFoundException. Is it even possible to tell class loader, if class is not available in current class loader try looking in another?
Not generally, no. One could write such a classloader, but you can't 'edit' an existing classloader to work like this.
ClassLoaders are asked by either code itself (SomeClass.class.getResource will end up there, as will, of course, invoking findResource or loadClass or whatnot on an actual ClassLoader instance), or by the JVM (when a given class needs another to execute, the class's classloader is asked for it. This usually results in that CL returning it from cache, but if it hasn't been loaded yet by that CL, that would result in it being loaded).
The CL is then free to implement this request in any way it sees fit. URLClassLoader, which is also the default classloader (initialized with the classpath) will first ask its parent loader (in the default JVM config, that'll be the system loader that knows where e.g. java.lang.String lives, from the jmod files of your JDK installation), and return that result if available. It will then load by scanning classpath, and it ends there. You can't ask an existing URLClassLoader to change its behaviour, but you can of course write your own classloader - it's just code, you can extend the findClass etc methods.
Maybe elaborate a bit on what you're trying to accomplish. Why are multiple classloaders involved and what are you trying to accomplish by having multiple? (Say: Load classes from database BLOB fields, or, separate modules out, or, allow dynamic reloading of web handlers - that kind of answer).
Are you using an existing CL-based framework like OSGi, perhaps?
I'm developing a simple Plugin System and I basically want to control which classloader loads a class on a new instruction.
For instance I have a jar with my main program, and I distribute a class Foo.class in a extra packaged jar called Bar.jar.
I see three different possibilities to include the jar in my main program:
package Bar.jar with my main jar to include it in the classpath. This is obviously not feasible for a plugin system
Load the class Foo with an URL ClassLoader pointing to the jar. This would be too unfamiliar with the default java programmer to load classes manually via its name
Set a custom Classloader as the System-classloader via the -Djava.system.class.loader argument. But I dont really want to force the user to start his application with extra arguments.
Is there another way? Maybe something to register a Custom classloader for specific classes? or change the Classloader new uses at Runtime? Setting the ContextClassLoader of the Thread does not work.
When you load a class, the classes it refers to use the same class loader as it. This means to control the class loader used implicitly, you can to use a different class loader for the one which starts it all. e.g. Your first Runnable.
class A {
B b = new B();
The new B will chose the ClassLoader used for A (or a parent)
Setting the context class loader works for dynamic lookups like Class.forName(name); is the same as Class.forName(Thread.currentThread().getContextClassLoader(), name);
Once a class is loaded it will always use the same classes it depends on. It's not possible to swap different classes based on say a thread context. This means a class with a very specific classloader can use classes which are more generally used (e.g. as the general class is from a parent), however a more general used class cannot use a more specific class loader it is not aware of. i.e. ClassLoaders are not aware of their children.
One reason for this is that threads share memory. This means you can't say that when A creates a new B in one thread it will be different to another thread as the A instance could be accessed by either thread.
On different sites , Dynamic class loading is given as one of the reason of permgen problem.
As per my understanding , Dynamic class loading is loading the class as and when it is required.Alonwith that if Class A is loaded and it is referring another class B , it will also be loaded along with that. This is Dynamic class loading. Right? If yes, this is essential and inbuilt feature of JVM. What we can do about it?
Or my understanding is wrong here. when we say Dynamic class loading , are we reffering to custom class loaders here?
My last question related to above is, Class is loaded once by customer loader. So when we do hotdeployment on application server, how appserver loads the new version of class. Does it use different class loader here?
No, dynamic class loading refers to loading classes during runtime that are unknown at compile time, e.g., via Class.forName, or reflection (1, 2).
I am doing a JBoss SEAM project and when I view a form I get this error.
java.lang.ClassCastException:
it.cogitoweb.csi.entity.csiorelav.CsiTipoLav cannot be cast to
it.cogitoweb.csi.entity.csiorelav.CsiTipoLav
Its alway the same JPA class which is related to the form which is shown on the screen, it doesn't make sense to me why is it the same class, it seems impossible.
This happens when two different ClassLoader objects load classes with the same name. The equality of two classes in Java depends on the fully qualified name and the class loader that loaded it.
So if two independent class loaders load classes from the same location, then objects of those types will not be able to be cast to each others type, even if their classes are called the same.
As Joachim explained earlier, java.lang.ClassCastException typically occurs when two classloaders load the classes with the same name. However, i have come across another situation when this could occur.
This could occur with some IDE's that automatically reloads classes that have been modified. In such cases there might be older versions of the class retained in memory causing ClassCastException.
Here are a few ways you could resolve this issue :
If you are writing a custom class loader, while loading a class make sure that the base/default class loader does not already have an instance of that class loaded.
Make the class being loaded a sub-class of the class that is already loaded by the default class loader.
Make the class being loaded implement an interface that is already loaded by the default class loader.
More info here - http://www.jspwiki.org/wiki/A2AClassCastException
This is because the class has been loaded by two different classloaders. You cannot cast between them.
You've likely got a duplicate copy of CsiTipoLav in your application, and the two different copies are being loaded at different times from different classloaders. JBoss has a plethora of different classloaders in a hierarchy, and it's easy to get things in a twist.
Make sure you only have one copy of the class.
The object you are trying to cast, is loaded by a different classloader than the one which has loaded the class you are trying to cast into.
In my case i had two different *.ear and wanted to load a class from the other.
So i had to isolate the classloader. I used this description:
http://www.thorgull.be/wiki/index.php?title=ClassLoader_isolation_in_JBOSS
It worked for me.