I have an SPI interface defined in a maven module A. In Module B, which is a spring-boot application, I have defined META-INF/services/<interface-named-file>.
In Module A, I am having this code.
public class NotificationResultPluginProvider {
private static NotificationResultPluginProvider notificationResultPluginProvider;
private NotificationResultPlugin notificationResultPlugin;
private NotificationResultPluginProvider() {
final ServiceLoader<NotificationResultPlugin> loader = ServiceLoader.load(NotificationResultPlugin.class);
final Iterator<NotificationResultPlugin> it = loader.iterator();
if (it.hasNext()) {
notificationResultPlugin = it.next();
}
}
public static synchronized NotificationResultPluginProvider getInstance() {
if (null == notificationResultPluginProvider) {
notificationResultPluginProvider = new NotificationResultPluginProvider();
}
return notificationResultPluginProvider;
}
public NotificationResultPlugin getNotificationResultPlugin() {
return notificationResultPlugin;
}
}
In Module B - spring boot app - I have an implementation of NotificationResultPlugin interface.
Now here is the pickle.
When I run the boot app from intellij, I see that (in below code) it.hasNext() is true and notificationResultPlugin is found. In this case my application is working as expected.
if (it.hasNext()) {
notificationResultPlugin = it.next();
}
But when I run the boot app with CLI, using a command like below (note I am deflating the jar first and then launching)
jar -xf <jar file>;
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12341 -cp 'BOOT-INF/lib/*:BOOT-INF/classes' <main/class/fqn>;
Then it.hasNext() is false and my implementation in Module B for given SPI is not found. As a result, my application is not working as expected. I am at wits end now.
Other relevant information:
My spring boot app, is not a web app. That is I am not exposing any rest end point. I am simply using spring-kafka with minimal dependencies.
What am I missing ? Any help is appreciated.
Found solution
As they say, mind works best when you are not trying.
ServiceLoader was not able to load the SPI implementation because META-INF/services directory was not in classpath while I am starting the application. Setting the class path correctly did the trick. Ergo, this is the change i needed to do.
-cp 'BOOT-INF/lib/*:BOOT-INF/classes:.'
Notice that extra dot at the end.