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

I am trying this right now. It actually works, but the problem is that the generated META-INF/servicecs/XXX files only exist in the JAR.

However, I need them for the unit tests to run, so they need to be on a Maven source/resource folder. Is there some way I can tell the bnd to materialize these files on the file system instead of just dropping them into the final JAR?

just guessing: maybe somewhere near -target-dir and maybe some manual copying with system (docu is not good… but @juergen-albert has a pending PR with some docu … maybe enough to get the idea)

In maven they should also be on the file system. In bndtools you should be able to use the JAR in Junit?

I didn’t find them on the file system. When running tests via bnd, it is not a problem. However, I also run my tests using the surefire maven plugin and using the IDE (Eclipse) and in both cases, I need the files to be present on the file system and not only in the JAR.

I guess you need to file an issue. The maven plugin specifically creates the files on the filesystem. In the other envs. only the JAR is generated.