简体   繁体   中英

Java ClassLoader - force reloading already loaded classes

I'm currently trying to load classes into my application so that I can then filter out those that don't contain any test / @Test -methods. I want to run these tests in my application afterwards.

So far, so good - except it seems like the URLClassLoader I'm using (or probably any ClassLoader ) doesn't actually reload classes that are located on my applications classpath.

More precisely, a user of my application starts by selecting a number of .java source files. Those are then copied to a temporary location and a number of regex match/replace pairs are applied to the copy of the original source files. Next, the copies are compiled, and I then want to load those compiled .class -files into my application so I can run them as tests.
In most cases, this works as desired.

Unfortunately, if the fully qualified class name (FQCN) of any of the selected files is identical to the FQCN of a class that is part of this application (such as tests for this application), the ClassLoader ignores the specified path (to %temp%\\myfolder\\ ) and the (updated) version of the class file located there, but instead uses the already present/loaded version of the class.

After some research, this behaviour can be expected according to the docs (emphasis mine):

• The loadClass method in ClassLoader performs these tasks, in order, when called to load a class:
- If a class has already been loaded, it returns it.
- Otherwise, it delegates the search for the new class to the parent class loader.
- If the parent class loader does not find the class, loadClass calls the method findClass to find and load the class.

I tried using findClass , but it's unfortunately not visible.

Hence my question - does anyone know how to force java / the ClassLoader to actually load the class from the specified path, ignoring any - FQCN-wise - identical existing classes?

A classloader first delegates to its parent classloader, which is how it determines "if a class has already been loaded". If you want to force a classloader to load a new class, one way is to insert another classloader in the chain which fails to load/find the same class. Very quick, incomplete example:

class FirewallLoader extends ClassLoader {
    public FirewallLoader(ClassLoader parent) {
        super(parent);
    }
    public loadClass(String name, boolean resolve) {
        if (name.equals("some.class.Xyz")) {
            throw ClassNotFoundException();
        }
        super.loadClass(name, resolve);
    }
}

You make the "FirewallLoader" the parent or your URLClassLoader, and then your URLClassLoader will load new versions of whatever classes the Firewall loader filters out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM