ServiceLoader and ModuleLayer

Sander Mak sander.mak at luminis.eu
Tue Sep 26 19:37:14 UTC 2017


I'm currently running into an issue that behaves unexpected as far as I can see. Let's say there are two service types, A and B. The module `main` in the boot layer has a uses constraint on A. Module `main` instantiates a new ModuleLayer with the following code:

      ModuleFinder finder = ModuleFinder.of(dir.toPath());

      ModuleLayer parent = ModuleLayer.boot();
      Configuration cf = parent.configuration()
        .resolveAndBind(finder, ModuleFinder.of(), Set.of());

      ClassLoader scl = ClassLoader.getSystemClassLoader();
      ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl);

      // Now use new A providers from the layer:
      ServiceLoader.load(layer, A.class).forEach(...)

When `dir` contains a single provider module that provides an implementation of A, this works fine. What doesn't work, is if I have a directory with a provider module providing an A implementation, where this A implementation in turn has a uses constraint on B. When I check `layer.modules()`, I can see that the B provider modules do get resolved into the layer (they're also in `dir`). However, `ServiceLoader.load(B.class)`, which is part of the A service implementation code, returns no instances. How can I make sure the B service providers are bound as well within the layer?

To answer my own question, after some thinking and experimentation I found out that the A implementation should use the following code:

     ServiceLoader.load(getClass().getModule().getLayer(), B.class)

So... should I start writing all my ServiceLoader calls this way from now on, if I want to make sure my modules work regardless of whether they're loaded in the boot layer or another layer? Wouldn't it be more logical for ServiceLoader to always work from the current layer (hm, that would probably break the current classloader based contract)? Am I missing another option?


Sander





More information about the jigsaw-dev mailing list