JPMS ServiceLoader does not work for me as expected.
I am trying to provide a desktop program as an executable jar with a default service, that can be overloaded by the individual user. A user provides their own service class and give their name as an argument on the commandline.
The service:
package eu.ngong.myService;
public interface MyService {
public String name();
public void doSomething();
}
The program together with the default service (the first lines in the if and the for are inserted for logging):
package eu.ngong.myService;
import java.util.ServiceLoader;
public class ServiceUser implements MyService {
private static MyService myService = new ServiceUser();
public static void main(String[] args) {
if (args.length > 0) {
System.out.println("trying to load " + args[0] + " envirionment.");
ServiceLoader<MyService> myServices = ServiceLoader.load(MyService.class);
for (MyService ms : myServices) {
System.out.println(ms.name());
if (ms.name().equalsIgnoreCase(args[0])) {
myService = ms;
}
}
}
myService.doSomething();
}
@Override
public void doSomething() {
System.out.println("The default service is acting.");
}
@Override
public String name() {
return "Default";
}
}
Both collected in myService.jar with the main class of ServiceUser hosting the module-info.java
module MyService {
exports eu.ngong.myService;
provides eu.ngong.myService.MyService with eu.ngong.myService.ServiceUser;
}
An individual jar at a user may be
package eu.ngong.user1;
import eu.ngong.myService.MyService;
public class User1 implements MyService {
@Override
public String name() {
return "User1";
}
@Override
public void doSomething() {
System.out.println("User1 is acting.");
}
}
with the module-info.java
module User1 {
requires MyService;
provides eu.ngong.myService.MyService with eu.ngong.user1.User1;
}
However, running the program with
java -p ..\user1\user1.jar;myService.jar -jar myService.jar User1
leads only to the unexpected output
trying to load User1 environment.
The default service is acting.
While I expected with logging
trying to load User1 environment.
Default
User1
User1 is acting.
What did I miss?
You need to declare
uses eu.ngong.myService.MyService;
in the module where you want to execute the service loading code.
META-INF/services
for the correct resolution of modules via jar files if processed as automatic.Since this wouldn't fit in the comments, hence sharing the findings of a similar example here. I could notice upon execution via IntelliJ that the code just worked with the uses
declaration and the classpath of user-service
module.
Further I tried to use a similar command line:
java --show-module-resolution -p base-service/target/classes:user-service/target/classes --add-modules base.service,user.service -m base.service/base.service.ServiceUser user1
root base.service file://.../base-service/target/classes/
root user.service file://.../user-service/target/classes/
user.service requires base.service file://.../base-service/target/classes/
base.service binds user.service file://.../user-service/target/classes/
...
trying to load user1 environment.
Services found : 2
User1
Default
User1 is acting.
and added the --show-module-resolution
to seek why providing the jar's on the module path didn't work. The output was as follows and had a difference where the service module was not able to bind the user module.
java --show-module-resolution -p base-service/target/base-service-1.0-SNAPSHOT.jar:user-service/target/user-service-1.0-SNAPSHOT.jar --add-modules base.service,user.service -m base.service/base.service.ServiceUser user1
root base.service file://...base-service/target/base-service-1.0-SNAPSHOT.jar automatic
root user.service file://...user-service/target/user-service-1.0-SNAPSHOT.jar
user.service requires base.service file://...base-service/target/base-service-1.0-SNAPSHOT.jar automatic
.....
trying to load user1 environment.
Services found : 1
User1
User1 is acting.
This might be the cause for unexpected output in the way you are executing as well. The slight difference being the Default
implementation is not resolved in the latter for me.