Loading class with interface from another class loader - java

I have a class Foo which implements an IDoMagic interface.
The Foo class is loaded by the system classloader and the IDoMagic interface is defined in a third party component, which I think loads the interface in another class loader (Dynamic Classloader).
When I try to create a new instance of Foo, I'm getting a NoClassDefFound for IDoMagic. I assume that's because it is loaded by a different class loader.
I have tried to create a BridgeClassLoader (similar to the one used by Guice) and then load class Foo from the system class loader and all other classes from a different classloader which I think is the one used for IDoMagic but without any success.
Is there a way around it?

Classloaders (CL) in Java work on a delegate strategy which means that the CL first will ask her parent, which also asks her parent, if she knows the defintion for class X. Only if neither the parent nor any of the ancestors or the current classloader knew the classdefinition for X then the current classloader will load the definition from the respective X.class file.
If a class Foo is loaded by the system classloader, any classes Foo is dependend on need also be loaded by either the system CL or by a parent of this CL. As IDoMagic is provided in an other JAR, you most likely need to add this JAR file to the classpath (java -cp ... or java -jar ...). Due to the delegation model, any CL which is a (grand-; and so forth)child of this CL will also gain access to the class definitions loaded by any of the parental CL.
If IDoMagic needs to be loaded by a custom CL, Foo must not be loaded by the system CL but with either the custom CL or a child of this CL in order for the delegation strategy to kick in and provide the definition for IDoMagic if Foo is loaded/instantiated.
There is a custom delegation CL model where shared classes are kept in a kind of common CL list/array which may be used by dependend CL. The dependend classes are not direct children of the common CLs but are children to a delegation CL which simply delegates calls to the common ones before asking the parent if neither of the children was able to execute the task. One solution here might be a structure like this:
bootstrap CL
- system CL
- delegation CL
- common CL
- plugin CL
- plugin 1 CL
- plugin 2 CL
Here, the delegation CL needs to delegate an invocation of loadClass(...) and findClass(...) to its contained common CL (object composition) and only if it couldn't find a definition delegate the call to his parent. Similar to this still experimental class
This delegation loader enables to load IDoMagic with the common CL f.e. and the Foo class with one of the plugin loaders, which is not a direct child of the common CL. However, this requires that the delegation CL propagetes all calls to the common CL first before asking the parent. Also, this delegation loader brings some overhead to the table as it makes one of the adavandages of custom CL (the unloading of unused classes) more difficult.

If a class loader receives a class load request, it does not self-load
Instead, the request is delegated to the loader of the parent class. If the parent class loader still has its own parent class loader, it is further requested
The request will eventually reach the top-level starting class loader, and if the parent class loader can complete the class loading task, it will return successfully
If the parent loader is unable to complete the load task, the child loader will try to load it itself. This is the two-parent delegation model.

Related

ClassLoader in Java

I was playing with classloaders in java and found the following behavior. I could logically reason out about this, but I'm not sure what I'm assuming is completely true. I'd like to know more formal explanation of this behavior.
What I was trying?
So I had the following code:
URL[] classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");
// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();
Now the last line gives me a ClassCastException.
My reasoning (guess) about why I'm getting a ClassCastException: The classloader of personClass is urlClassLoader whereas the classloader of Person class is actually application class loader or system class loader (please correct me if I'm wrong). These class loaders don't match and I'm getting a ClassCastException. (I'm here assuming that when typecasting a check is performed on the classloaders)
So now I continue exploring and alter the construction of URLClassLoader in the following way:
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());
Here Main is the enclosing class. The above line saves me from a ClassCastException.
My reasoning (guess) about this: As now the urlClassLoader has application class loader as its parent (this application class loader is same that is used to load Person class), while trying to cast, Java check if the classloaders match and this check continues with the parent of the urlClassLoader, after going one step up the classloaders match and there is no ClassCastException.
I assume that the classloader of the class of the object to be typecasted is checked against the classloader of the class into which you need to typecast and if this don't match the parent of the classloader of the class of object is tried for the match and this continues.
Please correct me if I'm wrong at any point and also provide pointers to the formal documentation of this behavior.
I have seen this link, but this don't provide the details I've asked.
The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
Invoke findLoadedClass(String) to check if the class has already been loaded.
Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
Invoke the findClass(String) method to find the class.
If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.
So if you set the parent class loader, this line:
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");
behaves the same as
Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");
if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).
You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.
Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.
Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".

Difference between Thread.currentThread() classLoader and normal classLoader

Can you tell me what is the difference between Thread.currentThread().getContextClassLoader() and TestServlet.class.getClassLoader() do not mark it as duplicate and also please explain as well as provide me example when to use these
Java File:
package com.jar.test;
public class TestServlet {
public static void main(String args[]) {
ClassLoader cls = TestServlet.class.getClassLoader().loadClass(
"com.jar.test.TestServlet");
ClassLoader cls = Thread.currentThread().getContextClassLoader()
.loadClass("com.jar.test.TestServlet");
}
}
Thread.currentThread().getContextClassLoader()
Returns the context
ClassLoader for this Thread. The context ClassLoader is provided by
the creator of the thread for use by code running in this thread when
loading classes and resources. If not set, the default is the
ClassLoader context of the parent Thread. The context ClassLoader of
the primordial thread is typically set to the class loader used to
load the application.
Class#getClassLoader()
Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader.
In a nutshell:
Thread.currentThread().getContextClassLoader() is the ClassLoader of the context of the thread that has been set with setContextClassLoader(ClassLoader cl). Imagine that you have a complex java application with a hierarchy of ClassLoader (for example an Application Server) and you want your current thread to load classes or resources from one specific ClassLoader in this hierarchy, you can do it by simply setting the context ClassLoader of the thread to this specific ClassLoader.
Class#getClassLoader() is simply the ClassLoader from which your instance of Class has been loaded.
Thread.currentThread().getContextClassLoader()
This is the current thread classloader and doesn't depend on the class calling it
TestServlet.class.getClassLoader()
This is the classloader that loaded the TestServlet class.
please explain as well as provide me example when to use these
Let's imagine you have Thread1 owned by ClassLoader1 and Thread2 owned by ClassLoader2. It's possible that you load your TestServlet class on Thread2 (by ClassLoader2) and then pass it to Thread1. At that point, if TestServlet needs to load a Class owned by ClassLoader1 it will need to use Thread.currentThread().getContextClassLoader(), as it's own ClassLoader is ClassLoader2 and not ClassLoader1.

Java ClassLoader not caching the class

I am trying to force some of the classes to be loaded using my custom class loader, the problem is after the loading the calling class still doesn't know about the class definition and tries to load it again, of course after that we have two different definitions of the class and assigning one to the other results in class cast exception.
Any pointers or ideas how this can be fixed?
This is the calling class:
CustomClassLoader loader = new CustomClassLoader(this.getPackageCodePath());
Class<?> midletClass = loader.loadClass(className);
midletClass.getMethod("InitEngine", Class.forName("android.app.Activity")).invoke(null, this);
ms_MIDlet = (MIDlet)midletClass.newInstance();//ClassCastException
And this is the class loader itself
public class CustomClassLoader extends PathClassLoader
{
public CustomClassLoader(String path)
{
super(path, getSystemClassLoader());//we set the parent to be the system class loader so the loading gets done in this class
}
#Override
public InputStream getResourceAsStream(String resName)
{
//...do some resource loading here
}
}
The calling class is running in some ClassLoader A. This classloader knows where to find and load MIDlet.class. Otherwise line 4 would produce a ClassNotFoundException for the cast.
You also use an instance of CustomClassLoader to load the Midlet.class.
On line 4 this blows up because you are casting the Midlet instance loaded by CustomClassLoader to a Midlet instances loaded by the ClassLoader A.
One solution is to make the CustomClassLoader logic delegate to ClassLoader A before loading a class itself. Something along the lines of first delegating a loadClass call to parentLoader.loadClass or getResourceAsStream to parentLoader.getResourceAsStream. If those calls fail then you can do your custom resource lookup.
This approach will make sure that all Midlet.class'es are actually loaded by the same classloader. You can check the delegation example at Java ClassLoader delegation model?

java : ClassLoaders

Say, I have a class A, loaded by ClassLoader CL1.
I have another class B, loaded by ClassLoader CL2.
Assume both classes are now loaded by their respective ClassLoaders.
From A, if I execute the following statement, what would be the result : B.class.getClassLoader();
Will it return CL2? Please clarify.
Thanks
HV
Will it return CL2?
In the case where it has permission to do so then yes - why wouldn't it? The result has no bearing on what class you execute the method from, it is to do with what class you execute the method on (which in this case, is B.class which was loaded by CL2.)
From the docs:
Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.
If a security manager is present, and the caller's class loader is not null and the caller's class loader is not the same as or an ancestor of the class loader for the class whose class loader is requested, then this method calls the security manager's checkPermission method with a RuntimePermission("getClassLoader") permission to ensure it's ok to access the class loader for the class.
So assuming it's an actual class that you've loaded (rather than a primitive), and the security manager says that you have permission to check the class, yes - it will return the corresponding classloader (CL2 in this instance.)
It does return the classloader which loaded class B but caller should have permission on that class loader.
Check the API doc
http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getClassLoader()

Problem with Java Class.forName

I'm trying to use Class.forName to dynamically load a class from a .jar file on the filesystem at runtime. The class I am trying to load implements an interface in another .jar file, so I am using my own URLClassLoader to reference the two .jars.
The code works when it is called not in the context of the web app (I have tested this by copying and pasting the method into a separate program and calling it from main). However, when I run/debug the web app (I'm using NetBeans) the code fails. The newInstance method throws a ClassCastException when I try to cast the instance to the interface specified in my jar_file_dependencies.jar.
Here is the relevant code if this helps:
File gameJar = new File("C:\\file_path\\jar_file.jar");
File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar");
URLClassLoader cl = new URLClassLoader(new URL[]
{
gameJar.toURI().toURL(),
gameDependenciesJar.toURI().toURL()
});
Class clazz = Class.forName("MyClass", true, cl);
IMyClass myClass = (IMyClass)clazz.newInstance();
System.out.println(game);
} catch (Exception e)
{
System.out.println(e.getMessage());
}
Any suggestions as to why this code is working in one program and not another would be greatly appreciated.
Many thanks,
Dan
short answer without going into too many of the hairy details: one or both of the gameJar and gameDependenciesJar probably contain a definition of the IMyClass class/interface. the rule of thumb when using child classloaders is that the child classloader should not contain any of the "shared" classes--these should exist only in the parent classloader.
partial explanation: Web app classloaders usually have different delegation policies from normal classloaders. often they prefer the child's class to the parent's. normal classloaders generally prefer the parent's class to the child's. in your web app, you are ending up with 2 separate definitions of the IMyClass class (one def in the parent classloader, one in the child). in your normal app, the IMyClass definition in the child classloader is being ignored, so only one definition gets loaded (in the parent classloader), and everything is happy.
Maybe this will help, (untested):
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
if (clsLoader == null) {
clsLoader = this.getClass().getClassLoader();
}
URLClassLoader cl = new URLClassLoader(new URL[]
{
gameJar.toURI().toURL(),
gameDependenciesJar.toURI().toURL()
}, clsLoader);
Also, you should pass a full declarative name of the class MyClass instead of just calling it MyClass in Class.forName().
E.g.
Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);

Categories

Resources