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.
Related
I know that Class instance loaded by different class loader can't be cast to each other.
But what if the one Class extends the other? I did an experiment and the result is confusing. Here is the ClassLoader I define:
public class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
if (name.startsWith("java")) {
return super.loadClass(name);
}
String filename = "/" + name.replaceAll("\\.", "/") + ".class";
InputStream is = getClass().getResourceAsStream(filename);
if (is == null) {
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (Throwable e) {
throw new ClassNotFoundException(name);
}
}
}
And the experiment code:
// These classes will be loaded by MyClassLoader
class Parent { }
class Child extends Parent { }
class MyCalendarData_aa_DJ extends CalendarData_aa_DJ { }
class MyAppleScriptEngine extends AppleScriptEngine { }
class MyBufferedReader extends BufferedReader {
public MyBufferedReader(Reader in) {
super(in);
}
}
public class DifferentClassLoaderCast {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = new MyClassLoader();
Class<?> pClass = classLoader.loadClass(Parent.class.getName());
Class<?> cClass = classLoader.loadClass(Child.class.getName());
// true, as pClass and cClass are loaded by same classloader
System.out.println(pClass.isAssignableFrom(cClass));
// false, different classloader
System.out.println(Parent.class.isAssignableFrom(cClass));
// true, why?
System.out.println(Object.class.isAssignableFrom(pClass));
Class<?> myCalendarData_aa_DJClass = classLoader.loadClass(MyCalendarData_aa_DJ.class.getName());
// false, CalendarData_aa_DJ is loaded by JAVA ext-classloader
System.out.println(CalendarData_aa_DJ.class.isAssignableFrom(myCalendarData_aa_DJClass));
Class<?> myAppleScriptEngine = classLoader.loadClass(MyAppleScriptEngine.class.getName());
// false, why? AppleScriptEngine is loaded by JAVA bootstrap-classloader
System.out.println(AppleScriptEngine.class.isAssignableFrom(myAppleScriptEngine));
Class<?> myBufferedReader = classLoader.loadClass(MyBufferedReader.class.getName());
// true, why? BufferedReader is loaded by JAVA bootstrap-classlaoder
System.out.println(BufferedReader.class.isAssignableFrom(myBufferedReader));
}
}
It seems that subclass loaded by MyClassLoader can be cast to superclass loaded by bootstrap class loader under package starts with java or built-in class?
// true, why?
System.out.println(Object.class.isAssignableFrom(pClass));
this one should be entirely obvious. Object is java.lang.Object and you rather clumsily call super.loadClass if the fully qualified name starts with java. Which means the loader of Object.class is the system loader, and this is true for all load ops: Whether classLoader loads Parent, or the system loader does, they both work off of the notion that j.l.Object.class is loaded by the system loader: The same type, therefore, compatible.
// false, why? AppleScriptEngine is loaded by JAVA bootstrap-classloader
System.out.println(AppleScriptEngine.class.isAssignableFrom(myAppleScriptEngine));
same reason. In reverse: the fully qualified name of AppleScriptEngine is not starting with "java".
Class<?> myBufferedReader = classLoader.loadClass(MyBufferedReader.class.getName());
// true, why? BufferedReader is loaded by JAVA bootstrap-classlaoder
System.out.println(BufferedReader.class.isAssignableFrom(myBufferedReader));
you guessed it. Because the FQN of BufferedReader starts with "java".
Perhaps you've misunderstood the classloading model.
The model that classloaders employ is a parent/child relationship. A classloader has a parent.
Any class is loaded by some classloader; if it hits any other class in its source code it will ask its own classloader to load it. But that loader may defer the job to any other loader. That's important. Your code will defer for any class whose FQN starts with "java" (and not even "java.", which is a peculiar choice). Otherwise, it loads itself. The classloader that is on record as THE loader of a class is the one that invoked defineClass. In your code, if you go via the if block that checks for starting with "java", your loader does NOT invoke defineClass, and therefore isn't the loader. If that if is not taken, you always end up invoking defineClass, making you the loader.
The common model for classloaders is this:
Ask your parent(s) to load the class, in order. If it can, great. We return that result, and that means the loader of said class is the parent and not you!
If not, then this loader will load it. Conflicts are unlikely; after all, the system loader couldn't even find it. Now you are the loader.
ClassLoader itself supports this model, but you get it by overriding findClass and NOT loadClass. The default impl of loadClass will do precisely as above: First calls the parents' loadClass methods, and only if those can't find it, will it invoke findClass to finish the job.
I strongly recommend you follow this flow, and update your code to extend findClass, not loadClass.
If you really want to load it yourself and NOT delegate to your parent loaders, then, yeah, overriding loadClass is how you do it. But now you have to deal with the fact that if it is a class that your parent can also find, that you can run into the scenario where your loader loaded, say, com.foo.Example, and parent did too, and whilst those classes have exactly the same name, as far as the JVM is concerned, they are completely unrelated and entirely incompatible with each other. The JVM doesn't mind, but it leads to highly confusing scenarios, where an object of type com.foo.Example cannot be assigned to a variable of type... com.foo.Example.
If you must do this, note that checking if it starts with "java" is highly suboptimal. For starters, "java." is a better fit, and for seconds, not all system classes start with "java". Ask the system loader first, if it can load it, defer to that (just return what it found), at the very least.
What are you trying to accomplish by writing a loader? With that insight, I can give more advice on which method (loadClass or findClass) is appropriate to override.
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.
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 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()