Automate META-INF/services chores

The Java Service Loader mechanisms has become quite important when JPMS started to enforce the module boundaries. It provides the crucial abstraction between the service you can use and the actual implementation class.

However, it does introduce a maintenance chore. The implementation class name must be placed in a file in META-INF/services that has the name of the service type. This can be a huge pita because not all IDEs will rename the file and its contents when the service type or the implementation class are refactored. And since it is in a corner of the build, it is easy to forget.

Although bnd was primarily designed to generate the meta data for OSGi, over time it add a myriad of functions that are actually quite useful, also for non-OSGi builds. One of these features is the ServiceProvider annotation. When you apply this annotation on an implementation class, it will automatically maintain the META-INF/services directory for you. If you refactor, it will automatically create the necessary files.

Since most open source projects already include the bnd-maven plugin, the only thing that is needed is to include the annotations. Since these annotations are all CLASS retention, this cannot introduce any runtime dependencies.

<dependency>
    <groupId>biz.aQute.bnd</groupId>
    <artifactId>biz.aQute.bnd.annotation</artifactId>
    <version>7.0.0</version>
</dependency>

You can then annotate any class to register as a ServiceLoader service.

@ServiceProvider(JsonProvider.class)
public class JsonProviderImpl extends JsonProvider {
    ...
}

The parameter to the annotation is the service type, the implementation class name is of course the class to which the annotation is applied to.

1 Like