1

I have three Jar files.All jar files contain Same class TestServicesImpl And Same Method displayWeLcomeMessage() But having different messages(output) of displayWeLcomeMessage(). Example :

public void displayWeLcomeMessage() {
        System.out.println("wecome msg of JAR version first");

    }

 public void displayWeLcomeMessage() {
            System.out.println("wecome msg of JAR version two");

        }

 public void displayWeLcomeMessage() {
            System.out.println("wecome msg of JAR version third");

        }

I have One main application and it contains jars included. My main application calls displayWeLcomeMessage() method.

first JAR is added in classpath and second JAR is loaded with custom classloader and invoke method displayWeLcomeMessage().

    File file  = new File("C:/Users/amitk/Desktop/Test_1.0.2.jar");
    @SuppressWarnings("deprecation")
    URL url = file.toURL();  
    URL[] urls = new URL[]{url};
    URLClassLoader  loader = new URLClassLoader(urls);

    Class classS = loader.loadClass("com.amit.servicesImpl.TestServicesImpl");
    Object object = classS.newInstance();
    Method getmsg = classS.getMethod("displayWeLcomeMessage");
     getmsg.invoke(object);

but it displays the same message as in method of JAR first. In my third JAR, i have changed the package name. that is com.amit.servicesImpl.TestServicesImpl is changed to com.amit.servicesImpl2.TestServicesImpl and this time it works properly that is message of method of JAR 3 is displayed here.

so let me know the main issue behind this.and solution for this.

Avyaan
  • 1,285
  • 6
  • 20
  • 47

2 Answers2

2

Maybe you have your JAR in your initial class loader. URLClassLoader will check existing class in parent class loader before checking in its own space.

1) You can extend and modify this behavior:

package com.mytool;

import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;

public class MyURLClassLoader extends URLClassLoader {

    private final Map<String, Class<?>> ourClasses = new HashMap<>();

    public MyURLClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public MyURLClassLoader(URL[] urls) {
        super(urls);
    }

    public MyURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = ourClasses.get(name);

            if (c == null) {
                // search in our paths
                try {
                    c = findClass(name);
                    ourClasses.put(name, c);
                } catch (ClassNotFoundException e) {
                    // ignore
                }
            }

            if (c == null) {
                c = findLoadedClass(name);
            }

            if (c != null) {
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }

            // default search
            return super.loadClass(name, resolve);
        }
    }
}

2) Or you can try to move our JAR and not load it at JVM start.

Note: Instead of using a full reflexivity, I'll use an interface loaded only by the initial classloader. Your object could implements it, and you'll be able to cast to this interface. If you do this with MyURLClassLoader, please don't add this interface in our dynamic loaded JAR!

Tyco
  • 131
  • 4
0

Classloader will pick that class which was found first. If you are having 10 packages having same class then only that class will be picked which was introduced first.

AJ.
  • 4,526
  • 5
  • 29
  • 41