Search code examples
javajava-9java-modulemodule-info

How to expand the module path at runtime


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).


Solution

  • 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.