7

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?

dzav
  • 545
  • 1
  • 10
  • 25
  • *"I have some class A:"* While some people think it is better to 'abstract a problem' to the point you can express it as obtuse symbols, I prefer some context that helps explain what is in class `A` that makes you want to load it dynamically. I.E. class `A` might be a `UserDefinedPlugIn` - the latter provides some context, the former does not. – Andrew Thompson Apr 17 '12 at 13:48
  • Ok, I can explain context of this question. I have class that reads images into `BufferedImage`. Sometimes it is `ImageIO.read(file)`, sometimes it is `Sanselan.getBufferedImage(file)`. I have my own class for saving images and I should create `BuffredImage` from file, then copy data from `BufferedImage` to my object. I want using some proxy class to catch all `#get(...)` methods call to save information in my object. – dzav Apr 17 '12 at 17:32

3 Answers3

4

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();

 }
josefx
  • 15,506
  • 6
  • 38
  • 63
  • Unfortunately, you can't define a non-default constructor in an interface (any constructor for that matter) the way vanveber has it. So, entre reflection... – mazaneicha Apr 17 '12 at 18:31
  • @mazaneicha you could bypass that by creating factory class and a factory interface (only if you really hate reflection). – josefx Apr 17 '12 at 21:21
3

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.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
0

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.

Cratylus
  • 52,998
  • 69
  • 209
  • 339