druvu-lib-loader

ServiceLoader, with the dependencies handed in at creation. Discovery was never the problem. Handing the implementation a Path, a Config, a DataSource was. Here the factory receives them, and the component is created valid, with no init() phase.

If your implementations are no-arg and unique, plain ServiceLoader already serves you. If a container such as Spring or Guice owns construction, keep it. This is for libraries and plugins that should not impose one.

View on GitHub Maven Central


Try it

Give the interface a static load(...), so callers need only one type:

public interface AccBook {
    String id();
    List<Account> accounts();

    // Convenience factory — discovers the implementation via ServiceLoader
    static AccBook load(Path path) {
        return ComponentLoader.load(AccBook.class, Dependencies.of(Path.class, path));
    }
}

In the implementation module, a factory:

public class GnucashBookFactory implements ComponentFactory<AccBook> {

    @Override
    public AccBook createComponent(Dependencies dependencies) {
        var path = dependencies.getDependency(Path.class);
        return new GnucashAccBook(path);
    }

    @Override
    public Class<AccBook> type() {
        return AccBook.class;
    }
}

Register it in META-INF/services/com.druvu.lib.loader.ComponentFactory, or in module-info.java:

provides com.druvu.lib.loader.ComponentFactory
    with com.myapp.gnucash.io.GnucashBookFactory;

Then:

AccBook book = AccBook.load(Paths.get("/path/to/file.xml"));

Your application code depends on the API module only.


What you get

  • Dependencies at creation. The factory receives type-keyed Dependencies; Dependencies.of(Path.class, path, Config.class, config) for several.
  • Fail-fast cardinality. ComponentLoader.load throws when several factories match, where findFirst() would silently pick one, and throws when none do.
  • The plugin case. MultiComponentLoader.loadAll(Plugin.class, deps) returns every implementation, each created with the same dependencies. disposeAll releases what it can and logs the rest.
  • Singletons. SingletonLoader.load once at startup, get everywhere else. A second load for the same type throws.
  • Still ServiceLoader underneath. JPMS provides and uses, no reflection scanning, no annotations, no container. An implementation with a no-arg constructor is found as a fallback without depending on this library at all.

Install

On Maven Central. Java 21 or newer. One runtime dependency, the SLF4J API: bring any binding, or none.

<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-loader</artifactId>
    <version>1.1.1</version>
</dependency>
implementation 'com.druvu:druvu-lib-loader:1.1.1'

With the Java module system: requires com.druvu.lib.loader; Before 1.1.0 the module was named druvu.lib.loader.

The full reference, every loader and the no-library fallback, is the README.


Something it almost does?

Open an issue, or write to me. If it is small and useful to more than you, I will often just build it.

Apache License 2.0.


Back to top

Copyright © 2026 druvu.com. All rights reserved.

This site uses Just the Docs, a documentation theme for Jekyll.