Understanding ClassLoaders in Java - java

I'm fairly new to the JVM and ClassLoaders. I have these two classes:
public abstract class CoreModule extends Entity
public final class EventManager extends CoreModule
At the start of the program, I create an instance of EventManager. So I understand that the JVM knows what Entity class is and how to load it (that is, it knows what ClassLoader to use), since EventManager is a grand-child. But when an Entity instance is passed by some serialization mechanism, it throws ClassNotFoundException. I have to manually set the ClassLoader to use (Event.class.getClassLoader()).
How come the JVM does not know what Event class is or how to load it if it already did it?

Actually the JVM does not figure this out "magically".
It is all based on a system class loader which will vary depending on the environment you use. Then each thread has a context ClassLoader which derives from this automatically.
The context ClassLoader you can change by using Thread.setContextClassLoader
If your serialization code should be able to resolve a class not visible from the context ClassLoader you need to set this the way you did.

Just by creating an instance of EventManager you didn't show the JVM how to load it. In fact, you're not talking to the JVM here. You're talking to one specific classloader, and when that same classloader is not in charge at the time of deserialization, you can get an error. That's why your problem is all about what clasloader is in charge at what point.

Related

Is it possible for class loader to get classes already loaded by different class loader?

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?

load multiple versions of the class file to the JVM

Is it possible to load multiple versions of the same class into the JVM. I have a version of the class "XYZ" loaded in the main thread and I have multiple children threads doing some work. I want to load different versions of class "XYZ" in to children threads.
Is this doable? I was thinking of creating a new context class loader for each of the children threads and use this context class loader to load a different version of the class. For now I am using URLClassLoader for context class loaders but that does not seem to work. Do I have to create a custom class loader to the do the job?
Here is the code I have so far.
final Thread builderThread = new Thread("Child Thread " + buildToken) {
#Override
public void run() {
futureTask.run();
}
};
try {
URL url = new URL("file:///path to the jar file");
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
classLoader.loadClass("XYZ");
builderThread.setContextClassLoader(classLoader);
}
The reason why I want to have different versions of the class is because I want to have different values for the static fields in the class "XYZ".
Yes, it is possible, and you're on the right track with URLClassLoader. The scope of your classloaders will be determined by the scope you want the static fields to have. For example, if each task or thread should have its own copy of those fields, then each task or thread must have its own classloader.
There are a couple other issues to be aware of. First, the class you want to load multiple times must not be found on the system classpath. This is because classloaders exist in a hierarchy, and delegate to their parent before attempting to load a class themselves. If the system classloader finds the class, it will load it only once, and other classloaders will use the class loaded by the system classloader.
Second, the JVM will treat each loading of the class as a distinct class, despite the fact that they're all identical. This means that instances of the dynamically loaded class must be confined to the scope of their classloader. If each task has its own classloader, then instances cannot be passed between tasks. And obviously you cannot publish instances to the rest of the app, because the rest of the app uses the system classloader, which must not know about the class. (You can get around this somewhat if the dynamically loaded class has a superclass or superinterface that the system classloader does know about. Then you can publish the instance as that type.)
The reason why I want to have different versions of the class is because I want to have different values for the static fields in the class "XYZ".
This really seems like a hack to me. Do you really have no other way to inject different values into this class?
How about passing some sort of Context instance for each thread and convert your class to use the settings from the Context instead of from static fields. You could also use a ThreadLocal so each thread would get the static field information from there instead.
Loading different versions of the class is going to be extremely hard (if not impossible) to debug. The only time I've ever heard of folks using multiple class loaders is when you have security concerns (often in a web server environment) and there is a deliberate point to having separation between the web classes and the outer admin classes.

What classloader does "new" use, and how do i change it?

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.

Enhancing a java object at runtime

I am aware that using proxy capable libraries (javassist, JDK dynamic proxies, etc) that it is possible to enhance a class to implement an interface at runtime.
My question is: is it possible to enhance an instantiated object to implement an interface at runtime (and likewise provide appropriate method handlers).
No, we can't change a class that has already been loaded. And we can't replace a loaded class (within a classloader).
There may be a chance if you
load a class with a custom classloader
unload the classloader (should unload the class aswell)
load the modified class again with a new classloader instance
But that is very, very black magic...

Getting class cast exception where both classes are exactly the same

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.

Categories