Avaje SPI

Discord Source API Docs Issues Releases
Discord Github Javadoc Github

The Java Service Provider Interface uses configuration files to find and load concrete implementations of given service provider interfaces. The downside of this system is that configuration files are not checked by the java compiler. As such it is a common occurence to forget to add the correct entries.

This zero-dependency library uses annotation processing to automatically generate the required META-INF/services entries for annotated classes. In addition, it will validate that the required provides clauses are present in an application's module-info files.


To use this library add the avaje-spi-service as a provided/optional dependency. (The dependencies need only be included at compile-time and are not required at runtime)


JDK 23+ note:

In JDK 23+, annotation processors are disabled by default, so we need to add a compiler property to re-enable.



On classes that you'd like registered, place the @ServiceProvider annotation. As long as you only have one interface/ superclass, that type is assumed to be the SPI interface. So given the example below:

public class BassServiceProvider implements MusicService {

Multi-Interfaced classes

If you have multiple interfaces and/or a base type, the library cannot infer the contract type. In such a case, we specify the contract type explicitly in the @ServiceProvider:

public class BassServiceProvider extends Instrument implements Stringed, MusicService {

Module Validation

For modular projects, the processor will validate that all the required provides clauses are accounted for. A compile error describing what `provides` statements are missing will be throw if validations fail. So given the following class and module-info:

public class BassServiceProvider implements MusicService {
module my.module {

  requires static io.avaje.spi;
  //provides not defined

You will get the compile error:

  Compilation failure /src/main/java/module-info.java:[1,1]
  Missing `provides MusicService with BassServiceProvider;`