I'm trying to call 2 different versions of the same dependency library (
jars
Main class
v1.jar
v2.jar
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
ClassLoader loader1 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-1.0.0-SNAPSHOT.jar").toURL() });
ClassLoader loader2 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-2.0.0-SNAPSHOT.jar").toURL() });
Class<?> c1 = loader1.loadClass("com.engine.na.EngineV1");
Class<?> c2 = loader2.loadClass("com.engine.na.EngineV2");
IEngine app1 = (IEngine) c1.newInstance();
IEngine app2 = (IEngine) c2.newInstance();
app1.run();
app2.run();
}
public Interface IEngine {
void run();
}
public class EngineV1 implements IEngine {
private File content;
private File en;
public EngineV1(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV1(args).run();
}
public void run() {
// some logic...
}
}
public class EngineV2 implements IEngine {
private File content;
private File en;
public EngineV2(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV2(args).run();
}
public void run() {
// some logic...
}
}
Exception in thread "main" java.lang.InstantiationException: com.engine.na.EngineV1
at java.lang.Class.newInstance(Class.java:427)
at com.engine.na.MainClass.main(MainClass.java:23)
Caused by: java.lang.NoSuchMethodException: com.engine.na.EngineV1.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 1 more
When you declare a no arg constructor in a class, the default constructor with no argument is not generated at compile time.
You have two ways :
adding explicitly a constructor with no argument.
invoking by reflection the constructor with an argument.
The first way is the easy trick and is a very generic way but it not necessarily the best way if it matters to value the state or one of part of the instance when it is created.
For this first case, it is self explanatory.
For the second case, the idea is you have to retrieve the constructor with argument from the class and specify the argument when you use it.
For example with this constructor :
public EngineV1(String value) {
...
}
You can invoke it in this way :
Class<EngineV1> c1 = (Class<EngineV1>)loader1.loadClass("com.engine.na.EngineV1");
Constructor<EngineV1> constructor = c1.getConstructor(String.class);
EngineV1 instance = ctor.newInstance("myString");