I'm using a library that loads some classes using Class#forName, but I need to change the implementation of some classes it loads. So I wrote a custom ClassLoader to replace the classes, but when invoking Class#forName it throws ClassNotFoundException even though the ClassLoader returned a Class object when requested.
Is that because the name of the classes mismatch? Is there a workaround while still using Class#forName?
I'm not able to reuse the package and name of the original class in the new one, otherwise I would've done that in compile time. But both classes extend the same class and only the interface of the super class is used throughout the code, so no incompatibility between them.
Example
REPL
https://replit.com/@t0rr3sp3dr0/Replace-Class-with-Custom-ClassLoader?v=1
Source
public class Main {
public static void main(String[] args) throws Throwable {
ClassLoader cl = new CL(Main.class.getClassLoader());
Class<?> clazzA = Class.forName("A", true, cl);
System.out.println(clazzA);
Class<?> clazzB = Class.forName("B", true, cl);
System.out.println(clazzB);
Class<?> clazzC = Class.forName("C", true, cl);
System.out.println(clazzC);
}
}
public class CL extends ClassLoader {
public CL(final ClassLoader parent) {
super(parent);
}
@Override
public Class<?> loadClass(final String name) throws ClassNotFoundException {
System.out.printf("name: %s%n", name);
switch (name) {
case "B", "C":
System.out.println("case: B or C");
return B.class;
default:
System.out.println("case: default");
return super.loadClass(name);
}
}
}
public class A {
public int i;
}
public class B {
public double d;
}
Output
name: A
case: default
class A
name: B
case: B or C
class B
name: C
case: B or C
Exception in thread "main" java.lang.ClassNotFoundException: C
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at Main.main(Main.java:8)