Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change default class loader in Java?

Let's say I have three classes, example.ClassA, example.ClassB, and example.ClassLoader. ClassA prints out HelloWorld and ClassB imports example.ClassA and invokes its main() method. If I do this:

java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassA

It works and uses my class loader. However, if I do this:

java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassB

ClassB uses my class loader, but ClassA (which was imported by ClassB) is loaded using a default class loader.

Is there any way to force Java to always use my class loader (unless another class loader is specified explicitly)?

EDIT: Thanks to Paŭlo Ebermann's answer below, I figured the problem is that I'm calling the parent class loader (URLClassLoader) to load the classes that I don't need to touch, and those loaded classes set that as it's context class loader, so classes imported from it uses the parent class loader of my custom loader. (confusing, sorry) Now I can get it to work by manually reading in EVERY class, however it seems redundant as I've copied URLClassLoader's code directly. Is there a way to tell the parent class loader to find and define the class, BUT set the Class's context class loader to your custom one?

like image 908
Yifan Avatar asked Jun 16 '11 01:06

Yifan


People also ask

How do I create a custom class loader?

To create a custom class loader, we will create a class that will extend ClassLoader. There is a method findClass() that must be overridden. Create a method that will load your given class from the class path. In our case we have created the method loadClassData() that will return byte[].

What is the use of ClassLoader in Java?

The Java ClassLoader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. The Java run time system does not need to know about files and file systems because of classloaders. Java classes aren't loaded into memory all at once, but when required by an application.

Can we create our own ClassLoader in Java?

We will create our own ClassLoader by extending the ClassLoader class and overriding the loadClass(String name) method. If the class name will start from com. journaldev then we will load it using our custom class loader or else we will invoke the parent ClassLoader loadClass() method to load the class.


1 Answers

If your class loader is implemented right, it will first ask its parent class loader about any classes that should be loaded.

The parent class loader of your loader will likely be the usual application class loader. This means that every class your class loader loads will first searched on the application class loader, and only if not found, on your one.

All classes which are defined by your class loader will also search their needed classes on your classloader. If they don't do, your ClassA is not really loaded by your loader.

If this does not help, you will need to show some code on how you got to your results.


An idea on what to do:

class ModifyingClassLoader extends URLClassLoader {

    // TODO: add constructors

    private boolean needsModifying(String name) {
        // TODO
    }

    private byte[] modifyClass(InputStream original) throws IOException {
        // TODO
    }

    public Class<?> findClass(String name) throws {
        if(needsModifying(name)) {
            try {
                InputStream classData = getResourceAsStream(name.replace('.', '/') + ".class");
                if(classData == null) {
                    throw new ClassNotFoundException("class " + name + " is not findable");
                }
                byte[] array = modifyClass(classData);
                return defineClass(name, array, 0, array.length);
            }
            catch(IOException io) {
                throw new ClassNotFoundException(io);
            }
        }
        else {
            return super.findClass(name);
        }
    }
}

To your question:

Is there a way to tell the parent class loader to find and define the class, BUT set the Class's context class loader to your custom one?

No. The ClassLoader of a class is always the one whose defineClass method was called to create the class. (The context class loader is something else - it is thread specific, and only used by classes which explicitly want to use it, not by classes resolving their own direct dependencies.)

like image 76
Paŭlo Ebermann Avatar answered Nov 16 '22 04:11

Paŭlo Ebermann