using URLClassLoader gets the same reference as the default ClassLoader - java

I'm trying to test that a class can be loaded to the jvm more then once but using different ClassLoader
so my code tries to load a class (class name "Tzvika") twice
first using the default ClassLoader
and in the second try using the URLClassLoader
the problem is that i get the same reference for the URLClassLoader and the default ClassLoader
what i'm doing wrong?
here code:
public static void main(String[] args) {
Tzvika t1 = new Tzvika();
System.out.println("t1 class loader: " + t1.getClass().getClassLoader());
Tzvika t2 = null;
try {
URLClassLoader clsLoader = URLClassLoader.newInstance(new URL[] {new URL("file:/C://data/workspace/ashrait/tests/SampleClassLoader/bin/com/tzvika/sample/")});
// same problem when i do this
//URLClassLoader clsLoader = new URLClassLoader(new URL[] {new URL("file:/C://data/workspace/ashrait/tests/SampleClassLoader/bin/com/tzvika/sample/")});
Class cls = clsLoader.loadClass("com.tzvika.sample.Tzvika");
t2 = (Tzvika)cls.newInstance();
System.out.println("t2 class loader: " + t2.getClass().getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
here my console output:
t1 class loader: sun.misc.Launcher$AppClassLoader#1a52fdf
t2 class loader: sun.misc.Launcher$AppClassLoader#1a52fdf

Create the URLClassLoader without a parent.
URLClassLoader clsLoader = URLClassLoader.newInstance(new URL[] {new URL("file:/C://data/workspace/ashrait/tests/SampleClassLoader/bin/com/tzvika/sample/")}, null);
Note also that you should specify the path to the root of the classpath, ie.
URLClassLoader clsLoader = URLClassLoader.newInstance(new URL[] {new URL("file:/C://data/workspace/ashrait/tests/SampleClassLoader/bin")});
To better clarify, the constructor of URLClassLoader states
The URLs will be searched in the order specified for classes and
resources after first searching in the specified parent class loader.
So when you try to load a class from this ClassLoader, it will first check the parent ClassLoader, which is the bootstrap classloader, for the existence of that class. Since that parent class loader has already loaded a com.tzvika.sample.Tzvika class, it will return it.
Now, since the classes loaded by the parent class loader and your clsLoader are different, the instances of these classes therefore belong to different classes. So although you have com.tzvika.sample.Tzvika from both ClassLoaders, they are very much different.
That's the whole point of different ClassLoaders.

Related

BootstrapClassLoader not loading in the Delegation Model

I am just revisiting the JVM concepts and was try to do a delegation check. Consider the below code
public class SrkDelegationDemo {
public static void main(String[] args) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
while (true) {
System.out.println("ClassLoader is " + cl);
ClassLoader parent = cl.getParent();
if (parent == null) {
System.out.println("Last Classloader which has no parent = " + cl);
// This line should print Bootstrap
break;
}
cl = parent;
}
}
Output
ClassLoader is sun.misc.Launcher$AppClassLoader#ab770638
ClassLoader is sun.misc.Launcher$ExtClassLoader#75c10082
Last Classloader which has no parent = sun.misc.Launcher$ExtClassLoader#75c10082
I am expecting the BootstrapClassLoader as well from what I've read online, not sure of this.
I am using adopt-openjdk-with-openj9-jvm and JDK version is jdk8u212-b03
Bootstrap class loader has no corresponding java.lang.ClassLoader object; its implementation is inside JVM. Otherwise who will load java.lang.ClassLoader class?
As the specification of ClassLoader.getParent says,
Some implementations may use null to represent the bootstrap class
loader. This method will return null in such implementations if this
class loader's parent is the bootstrap class loader.
OpenJDK is exactly such implementation.

Calling a outside class method from Jar class

I have created a class "Class B"
package com.b
public class B
{
public void printMsg()
{
System.out.println("Called");
}
}
I have created a jar file with below class "Class A"
package com.a
import com.b
public class A extends B
{
}
When i tried to load jar dynamically using below code, I am getting error "Class B" "classnotfoundexception"
ClassLoader cl = new URLClassLoader(new URL[] { new URL(jarFullPath) });
Class<?> cla = cl.loadClass(className);
Object obj = cla.newInstance();
I believe that it is because you did not provide any parent ClassLoader to your URLClassLoader such that it can find A but not B, try this instead:
ClassLoader cl = new URLClassLoader(
new URL[] {new URL(jarFullPath)}, Thread.currentThread().getContextClassLoader()
);
This use Thread.currentThread().getContextClassLoader() as parent ClassLoader corresponding to the context ClassLoader.

Need a Java system-only class loader

I would like to find or create a Java class loader that loads only system classes, excluding any classes on the application defined class path. My goal is to use that class loader to build a class loader that loads from a specific JAR file, resolving system classes using the system-only class loader, but not contaminating the classes from the JAR file with any classes defined by my application.
So far I have not found any way to create a system-only class loader that does not either use private APIs or make assumptions about the Java implementation. See code below that works in my current environment but makes undesirable assumptions.
If there is no way to create an implementation independent system-only class loader, is there a reason why not? Is what I am trying to do a bad idea?
private ClassLoader createJarClassLoader(File f)
{
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (systemClassLoader instanceof URLClassLoader) {
URLClassLoader cl = (URLClassLoader) systemClassLoader;
URL[] urls = cl.getURLs();
List<URL> wantedURLs = new ArrayList<>();
for (URL u : urls) {
if (isSystemURL(u)) {
wantedURLs.add(u);
}
}
try {
wantedURLs.add(f.toURI().toURL());
} catch (MalformedURLException ex) {
return null;
}
return new URLClassLoader(wantedURLs.toArray(new URL[0]), null);
}
return null;
}
private boolean isSystemURL(URL u)
{
return u.getPath().contains("/jre/");
}
You need to set the parent ClassLoader to be the bootstrap ClassLoader. Call getClassLoader() on a java.lang.String object to get the bootstrap ClassLoader and use that in your ClassLoader constructor.
public class MyClassLoader extends URLClassLoader {
protected MyClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
static MyClassLoader getInstance(URL[] urls) {
ClassLoader parent = "".getClass().getClassLoader();
return (new MyClassLoader(urls, parent));
}
}
The representation of the bootstrap classloader is documented as implementation dependent
Some implementations may use null to represent the bootstrap class loader. This method [getClassLoader] will return null in such implementations if this class was loaded by the bootstrap class loader.
but the same wording applies to parent ClassLoader in the ClassLoader constructor, which means that this solution is portable.

How to load .class and call one of its methods

I've compiled at runtime a java file on file system which is a very simple class:
public class Test {
public static int res(int a, int b) {
return a*b;
}
}
now I just want to call res method from my project (that will be a jar), but my code produce java.lang.ClassNotFoundException: Test
and this is how I've loaded the class:
URL[] urls = new URL[] {new URL("file:///"+UtilOverriding.getFile1().replace("java", "class"))};
URLClassLoader loader = new URLClassLoader(urls);
Class clazz = loader.loadClass("Test");
When you specify a class path you have to provide the directory which is the parent to all your packages. Try instead.
new URL("file:///"+UtilOverriding.getFile1().getParent()}

Why isn't there a .getURLs() in ClassLoader?

In another answer, I wrote the following code (Java 7):
public final class Foo
{
public static void main(final String... args)
{
final ClassLoader loader = Foo.class.getClassLoader();
final URL[] urLs = ((URLClassLoader) loader).getURLs();
for (final URL url : urLs) {
System.out.println(url);
System.out.println(Files.probeContentType(Paths.get(url.toURI())));
}
}
}
I had to cast the ClassLoader to URLClassLoader in order to have the .getURLs() method.
This is not the first time I've been doing it, and this cast has never failed for me.
Looking at the type hierarchy, I see that:
URLClassLoader -> SecureClassLoader -> ClassLoader
My question is why doesn't ClassLoader define .getURLs()? Are there concrete examples of class loaders being unable to return URLs?
Just search through grepcode. For example JBoss' ModuleClassLoader does not extend URLClassLoader

Categories