0

I have a jar file that I load dynamically, inside it there is in lib/ another jar (external library) that I use in main (import it.xxx.xx). How do I load also this external library dynamically in classpath? My code doesn't work:

public static void runOne(String jar, String class_name, Optional<String> test_name, 
TestExecutionListener listener) throws Exception {
        Launcher launcher = LauncherFactory.create();
        
        ClassLoader loader = URLClassLoader.newInstance(
                new URL[] { new File(pathJars+"/"+jar).toURI().toURL() },
                ServiceUtil.class.getClassLoader()
        );

        loader.getClass(); 

        addURL(loader); <--here i want add a jar to classpath!

        Class cls=loader.loadClass(class_name);
        Constructor constructor = cls.getConstructor();
        constructor.newInstance();

        LauncherDiscoveryRequest request;
        if (test_name.isPresent()) {
            Method m = cls.getMethod(test_name.get());
            request = LauncherDiscoveryRequestBuilder.request()
                    .selectors(selectMethod(cls,m))
                    .build();
        }
        else{
            request = LauncherDiscoveryRequestBuilder.request()
                    .selectors(selectClass(cls))
                    .build();
        }

        TestPlan testPlan = launcher.discover(request);
        launcher.registerTestExecutionListeners(listener);
        launcher.execute(request);
        //launcher.execute(request);
        loader=null;
        System.gc();

    }
    public static void addURL(ClassLoader loader) throws IOException {
        URL u=loader.getResource("lib/sem-platform-sdk-1.0-SNAPSHOT.jar");
        Class[] parameters = new Class[]{URL.class};
        URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class sysclass = URLClassLoader.class;

        try {
            Method method = sysclass.getDeclaredMethod("addURL", parameters);
            method.setAccessible(true);
            method.invoke(sysloader, new Object[]{u});
        } catch (Throwable t) {
            t.printStackTrace();
            throw new IOException("Error, could not add URL to system classloader");
        }//end try catch

    }//end method

Thanks

VGR
  • 40,506
  • 4
  • 48
  • 63
Catanzaro
  • 1,312
  • 2
  • 13
  • 24
  • Err, why do you want to do that? Cant you simply have the JARs in your classpath when your application starts? – GhostCat Aug 28 '20 at 11:58
  • no i have application 1 that is a consoleTest that load and start JunitTest in jar files. Application2 is test.jar that use internally an external library, if i open jar is in "lib" folder. From Application1 if i run a testMethod in test.jar i have error: java.lang.NoClassDefFoundError: Lit/almaviva/sem/sdk/MqttExecutor; – Catanzaro Aug 28 '20 at 12:46
  • Is something in here: https://stackoverflow.com/questions/12357136/reference-jars-inside-a-jar answer your question? – GhostCat Aug 28 '20 at 13:29

2 Answers2

0

This is generally done with a build tool (e.g. maven or gradle). I don't know if you are using one of these. They make life so much easier.

We use Maven with the Apache Shade plugin to do exactly this. Maven has commands to set up the configuration for you automatically, then you add the Shade plugin to the resulting configuration file (pom.xml).

https://maven.apache.org/plugins/maven-shade-plugin/index.html

0

If I understand your problem correctly, you want the classes loaded from the jar file to be able to access the classes in the nested jar file. You can accomplish this by creating a ClassLoader with one entry for the jar file and another entry for the nested jar file.

Java has a special URL scheme, jar:, for referring to a jar entry directly. (This scheme and syntax is described in the documentation of JarURLConnection.) So you can construct your ClassLoader this way:

    URL jarURL = new File(pathJars+"/"+jar).toURI().toURL();
    URL semURL = new URL("jar:" + jarURL + "!/"
        + "lib/sem-platform-sdk-1.0-SNAPSHOT.jar");

    ClassLoader loader = URLClassLoader.newInstance(
            new URL[] { jarURL, semURL },
            ServiceUtil.class.getClassLoader()
    );
VGR
  • 40,506
  • 4
  • 48
  • 63
  • i've edit addURL(String jar) method with your code but still dont work : {"summary":{"ConnectionTest":"FAILED, Optional[java.lang.NoClassDefFoundError: Lit/almaviva/sem/sdk/MqttExecutor;]","JUnit Jupiter":"SUCCESSFUL"}} – Catanzaro Aug 30 '20 at 13:53