Reputation: 8657
i have a new little Swing project, i need to load same class from two different jarsm these jars is a third party so i dont have the source code.
for example i need to load myClass from the two jars. jar1.jar jar2.jar
simply i what i need to do :
public void doMyClassLogicVersion1() {
Loader = // here i need to load jar1.myClass.
// myClass need a two params to initialize it in the normal case
// also i need to access its static members
// do the logic of myClass version1
}
public void doMyClassLogicVersion2() {
Loader = // here i need to load jar2.myClass.
// myClass need a two params to initialize it in the normal case
// also i need to access its static members
// do the logic of myClass version2
}
so can i do that, i know that is not good to this, but i really need to.
Upvotes: 0
Views: 1561
Reputation: 755
You can load new code into new class loaders relatively easily:
Case 1: If your classes have a common parent interface (or class) in current context, for example Runnable, you can use this code:
public void doMyClassLogicVersion1() {
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL1 },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();
}
public void doMyClassLogicVersion2() {
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL2 },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();
}
Case 2: If classes do not share a common parent:
public void doMyClassLogicVersion1() {
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL1 },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
// Avoid Class.newInstance, for it is evil.
Constructor<?> ctor = runClass.getConstructor();
Object obj = ctor.newInstance();
String methodName = "getName";
java.lang.reflect.Method method;
try {
method = clazz.getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) {
// ...
} catch (NoSuchMethodException e) {
// ...
}
try {
method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) {
// ...
} catch (IllegalAccessException e) {
// ...
} catch (InvocationTargetException e) {
// ...
}
}
public void doMyClassLogicVersion2() {
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL2 },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
// Avoid Class.newInstance, for it is evil.
Constructor<?> ctor = runClass.getConstructor();
Object obj = ctor.newInstance();
String methodName = "getName";
java.lang.reflect.Method method;
try {
method = clazz.getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) {
// ...
} catch (NoSuchMethodException e) {
// ...
}
try {
method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) {
// ...
} catch (IllegalAccessException e) {
// ...
} catch (InvocationTargetException e) {
// ...
}
}
Upvotes: 2
Reputation: 7799
Yes, you can do it. To avoid issues, I'd recommend you not to put any of the jars in the regular CLASSPATH, create 2 different threads, and set the ContextClassLoader of each thread to the corresponding jar before starting them.
Upvotes: 0