I have a library embedded in a jar which must load an external implementation :
- MyFile
- myjar.jar
- Myfirstclass.java
- MySecondclass.java
Knowing that :
My class dependent on my jar, my jar is executable and contains all the dependencies. It initializes the Reflection object in this way:
new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
I compile my class this way:
javac -cp /path/to/myjar.jar *.java
I then get:
- MyFile
- myjar.jar
- Myfirstclass.java
- MySecondclass.java
- Myfirstclass.class
- MySecondclass.class
In my jar, I'm trying to load these classes at runtime to initialize them. When I compile my jar with these two classes inside using Maven and run it, everything works fine.
Now I'm trying to run my jar like this:
java -cp . -jar /path/to/myjar.jar "myarg1" "myarg2"
But it does not work. Is my order wrong? The initialisation of the classpath? Or all my logic?
any help would be precious
EDIT : Following VGR's comment
I also tried this command which doesn't work:
java -cp .:/path/to/my/jar.jar mypackage.myrunnerwithmainclass "myarg1" "myarg2"
EDIT : Out of desperation I tried another approach with a ClassLoader
Here is my Runner class where I try to display the methods of the class :
package coderchallengeimpl;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
public class Runner {
private Runner() {
}
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
Runner.run(args[0]);
}
public static void run(String filePath) throws MalformedURLException, ClassNotFoundException {
List<URL> urls = filePathToUrl(filePath);
URL[] array = new URL[urls.size()];
urls.toArray(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
ClassLoader cl = new URLClassLoader(array);
Class<?> classCoderChallengeImpl = Class.forName("impl.CoderChallengeImpl", true, cl);
for (int i = 0; i < classCoderChallengeImpl.getMethods().length; i++) {
System.out.println(classCoderChallengeImpl.getMethods()[i].getName());
}
}
public static List<URL> filePathToUrl(String path) throws MalformedURLException {
File root = new File(path);
List<URL> urls = new ArrayList<>();
int i = 0;
for (File file : Objects.requireNonNull(root.listFiles())) {
if (file.getName().endsWith(".class")) {
urls.add(file.toURI().toURL());
System.out.println(file.getAbsolutePath());
}
}
return urls;
}
}
Voici le code de impl.CoderChallengeImpl :
package impl;
import coderchallengeimpl.CallBack;
import coderchallengeimpl.CoderChallengeJava;
public class CoderChallengeImpl extends CoderChallengeJava {
public CoderChallengeImpl(CallBack callBack, String path) {
super(callBack, path);
}
public void testMethod(){
this.addInputs("hello");
}
public void testMethod2(){
this.addInputs("hello");
}
}
Here is my console output:
/home/stan/Documents/Test/test/test_coderchallenge/java/CoderChallengeImpl.class
/home/stan/Documents/Test/test/test_coderchallenge/java/TestClassImpl.class
file:/home/stan/Documents/Test/test/test_coderchallenge/java/CoderChallengeImpl.class
file:/home/stan/Documents/Test/test/test_coderchallenge/java/TestClassImpl.class
java.lang.ClassNotFoundException: impl.CoderChallengeImpl
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:436)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:416)
at coderchallengeimpl.Runner.run(Runner.java:31)
at TestUnit.testRunner(TestUnit.java:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Process finished with exit code 255
Now if in the Runner I change the contents of the first parameter of the Class.forName line to java.lang.String it works fine I can see the list of methods of the String class.