I like services. I also like the module system. Unfortunately for me, before I used Java 9 I got in the habit of getting service providers from jars loaded at runtime via URLClassLoader
, something like this (I'll use Java 10's var
for brevity):
var url = new File("myjar.jar").toURI().toURL();
var cl = new URLClassLoader(new URL[] {url}, getClass().getClassLoader());
var services = ServiceLoader.load(MyService.class, cl);
for (var service : services) {
...
}
This works fine, even in Java 9 and beyond, but it loads the jar on the classpath, which means that it uses the old META-INF\services
method to find service providers. I would rather use the module-info
method, but that requires the jar to be loaded on the module path instead, but I couldn't find any way I might go about doing that. So here I am, hoping someone here who understands the module system more thoroughly will tell me how this can be done (or that it can't, if such is the case).
$JAVA_HOME/jmods is the directory containing java. base. jmod and the other standard and JDK modules. The directory mlib on the module path contains the artifact for module com.
A CLASSPATH is a sequence of classes' base paths and JAR files for the Java Compiler or JVM to locate the classes used in the application. Similarly, in JDK 9, a MODULEPATH is a sequence of modules' base paths and Modular JAR files for the Java Compiler or JVM to locate the modules used in the application.
Modules have taken so long because it makes fundamental changes to the way Java has worked since 1.0, and allows Java to move forward. It also allows Java to maintain compatibility while getting rid of legacy baggage (anyone still using RMI and Corba?).
The smallest working example, I could assemble, is
var path = Path.of("myjar.jar");
var cl = new URLClassLoader(new URL[]{path.toUri().toURL()});
var mf = ModuleFinder.of(path);
var cfg = Configuration.resolve(mf, List.of(ModuleLayer.boot().configuration()), mf, Set.of());
var ml = ModuleLayer.defineModulesWithOneLoader(cfg, List.of(ModuleLayer.boot()), cl).layer();
var services = ServiceLoader.load(ml, MyService.class);
services.forEach(System.out::println);
Assuming myjar.jar
is a modular jar declaring to provide MyService
implementations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With