I am trying to load plugins from a certain jar file using the java ServiceLoader with an UrlClassLoader, but I just cannot seem to get it to find my plugin classes. Building both modules works, but whenever I run the code below, I get a java.util.NoSuchElementException
, even though the file path is correct and I do not see where I messed up
I have to modules in my IntelliJ project, Test (The application loading the plugin and also providing the ServiceProvider) and PluginTest (The plugin to be loaded).
This is a screenshot of the structure of the Test module:
And here is a screenshot of the structure of the PluginTest module:
Here is the ServiceProvider PluginProvider:
package net.lbflabs;
public abstract class PluginProvider {
public abstract String getSecretMessage(int message);
}
This is the plugin that extends this class:
package net.lbflabs.plugins;
import net.lbflabs.PluginProvider;
public class PluginClass extends PluginProvider {
@Override
public String getSecretMessage(int message) {
return "Here is my secret.";
}
}
Here is the main class that loads the plugin:
package net.lbflabs;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ServiceLoader;
public class Main {
private static String path = "C:/Users/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar";
public static void main(String[] args) throws MalformedURLException {
System.out.println("Initializing... \nPreparing to load JAR from Path " + path + "...");
File file = new File(path);
System.out.println(file.exists()); //Prints true, so file does exist
URLClassLoader c = new URLClassLoader((new URL[]{file.getAbsoluteFile().toURI().toURL()}));
ServiceLoader<PluginProvider> loader = ServiceLoader.load(PluginProvider.class, c);
PluginProvider p = loader.iterator().next(); // Throws the java.util.NoSuchElementException
System.out.println("Secret message in plugin: " + p.getSecretMessage(1));
}
}
Here is the output when running the Tests module:
"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3\lib\idea_rt.jar=50330:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\jacke\IdeaProjects\Tests\out\production\Tests net.lbflabs.Main
Initializing...
Preparing to load JAR from Path C:/Users/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar...
true
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1310)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1298)
at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1396)
at net.lbflabs.Main.main(Main.java:19)
Process finished with exit code 1
The service file in the PluginTest module I believe is correctly named (net.lbflabs.PluginProvider
) and contains the valid class name (net.lbflabs.plugins.PluginClass
). If it was incorrect, IntelliJ would probably find the issue since when I introduce a typo I get warnings.
If someone needs it, I can provide the whole project as .rar (please tell me how you want me to share it, e.g. I create a onedrive link)
PS: I have already asked this question here, but since I was working on a bigger project and hesitant to share all the code in it (and since the only answer I got did not work, probably due to not enough info from me), I wanted to repost the issue with a minimum workable example that throws the same exception, I hope that is fine.
LazyClassPathLookupIterator
(an internal class) it actually catches theClassNotFoundException
and simply returnsnull
. Leading to the exception you get. – M. Deinum