Salah
Salah

Reputation: 8657

Loading same class from different jars

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

Answers (2)

Mohammad Dashti
Mohammad Dashti

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

Mario Rossi
Mario Rossi

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

Related Questions