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()
Related
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".
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.
In a question I asked earlier I got to know that in order to really be sure that some annotation is present or not somewhere in a class I need to reload it with a classloader that has access to both - the annotation and the class.
Now I'm struggling with how such a classloader would work. In my setup I just have the annotation as a java.lang.Class instance and the class that might be annotated with that annotation also as a java.lang.Class instance. Both might be loaded by some different classloaders I don't know anything about (classes might be loaded remotely, so they are not on the local file system).
While searching I found this JoinClassLoader
/**
* A class loader that combines multiple class loaders into one.<br>
* The classes loaded by this class loader are associated with this class loader,
* i.e. Class.getClassLoader() points to this class loader.
* <p>
* Author Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland, www.source-code.biz<br>
* License: LGPL, http://www.gnu.org/licenses/lgpl.html<br>
* Please contact the author if you need another license.
*/
public class JoinClassLoader extends ClassLoader {
private ClassLoader[] delegateClassLoaders;
public JoinClassLoader (ClassLoader parent, ClassLoader... delegateClassLoaders) {
super (parent);
this.delegateClassLoaders = delegateClassLoaders; }
protected Class<?> findClass (String name) throws ClassNotFoundException {
// It would be easier to call the loadClass() methods of the delegateClassLoaders
// here, but we have to load the class from the byte code ourselves, because we
// need it to be associated with our class loader.
String path = name.replace('.', '/') + ".class";
URL url = findResource(path);
if (url == null) {
throw new ClassNotFoundException (name); }
ByteBuffer byteCode;
try {
byteCode = loadResource(url); }
catch (IOException e) {
throw new ClassNotFoundException (name, e); }
return defineClass(name, byteCode, null); }
// some code omitted
} // end class JoinClassLoader
So my question is this:
Given a class instance of an arbitrary class C and a class instance of an annotation class A that may be loaded by arbitrary classloaders. A JoinClassLoader is instantiated with the classloaders of C and A in this order as delegating classloaders. Will that JoinClassLoader reload class C upon invoking findClass so that annotation A is always visible when C was actually annotated with it? If not how would such a classloader actually look like?
In a question I asked earlier I got to know that in order to really be
sure that some annotation is present or not somewhere in a class I
need to reload it with a classloader that has access to both - the
annotation and the class.
Given a class that has already been loaded by a classloader which might not have had access to all the annotations, I can believe that to be true. I think you've drawn the wrong conclusion, however.
If you want to be able to reflectively analyze a class's annotations at runtime, then the best solution is not to reload it. Instead, you should ensure that it is loaded in the first place by a classloader that can also see the annotations of interest. (And if that turns out not to be sufficient, then I don't see how you can expect reloading to help.)
In any case, reloading the class gives you a different class (of the same name), even if its bytecode is identical to that of the previously-loaded version. It is tricky to use this for anything but reflective analysis, and it is very difficult to be certain that the two classes actually do have identical bytecode. Reloading certainly does not replace the existing class with the newly-loaded one. All manner of fun can ensue.
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?
Say I have some Java code:
public class Widget {
...whatever
}
And some code that classloads the Widget:
ClassLoader widgetLoader = Widget.class.getClassLoader();
Can widgetLoader ever be null? Why/why not? If so, under what circumstances?
According to this method javadoc:
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.