dzav
dzav

Reputation: 555

Java ClassLoader change

I have some class A:

public class A {
    public A(String str) {
        System.out.println("Create A instance: " + str);
    }

    public void methodA() {
        System.out.println("#methodA1()");
    }
}

And my class loader implementation:

public class MyClassLoader extends ClassLoader {
    public MyClassLoader() {    
        super();
    }

    @Override
    public synchronized Class<?> loadClass(String name) 
            throws ClassNotFoundException {

        System.out.println("Load: " + name);

        return super.loadClass(name);
    }
}

And now I try to change default class loader in current thread:

import java.util.ArrayList;
import java.util.List;

public class ChangeLoaderTest {
    public static void main(String[] args) {
        // Save class loader so that we can restore later.
        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();

        MyClassLoader newLoader = new MyClassLoader();
        try {
            // Set new classloader.
            Thread.currentThread().setContextClassLoader(newLoader);

            // My class.
            A a = new A("1");
            a.methodA();

            // Standard Java class.
            List<Integer> list = new ArrayList<Integer>();
            list.add(2);
            list.add(3);
        } finally {
            // Restore.
            Thread.currentThread().setContextClassLoader(oldLoader);
        }
    }
}

And ChangeLoaderTest output:

Create A instance: 1
#methodA1()

No one

Load: ...

Why? How I can change ClassLoader into some thread?

Upvotes: 6

Views: 7469

Answers (3)

josefx
josefx

Reputation: 15656

As Marko Topolnik points out the context classloader is for use by frameworks. To use the classloader yourself you have to call loadClass("somepackage.A") and then use the reflection API to create a new instance of A (Class.newInstance()).

You wont be able to use A or its methods in your source directly since the calling code does not know A - it uses a different classloader. An interface or baseclass of A that can be loaded by the normal classloader can be used to avoid reflection.

interface AIF{
        void someMethod();
 }
class A implements AIF{
      public void someMethod(){}
 }


public void test(){
     MyLoader loader = new MyLoader();
     Class cla = loader.loadClass("A");
     AIF a = (AIF) cla.newInstance();
     a.someMethod();

 }

Upvotes: 4

Marko Topolnik
Marko Topolnik

Reputation: 200148

The contextClassLoader mechanisms is not used by the basic Java operations like new. It's only there so various frameworks can access the context class loader in charge and load resources, classes, etc. Java will always use the classloader that loaded the code that is executing. It's the one that you access via ChangeLoaderTest.class.getClassLoader() -- and there is nothing you can do about this one.

Upvotes: 3

Cratylus
Cratylus

Reputation: 54074

I think that what happens is that your application's class loader which is also your classloader's "parent" can locate A and load it. As a result your classloader will not be searched or used for loading A.

To be honest, I haven't much experience with classloaders but if you subclassed one that uses a URL for the path of the class (so that it can locate the class file) and the parent classloader can not load it (not part of classpath), your custom one will be used.

Upvotes: 0

Related Questions