No --add-provides patch option for test services ... case when APT generates test service

Rob Bygrave robin.bygrave at gmail.com
Fri Mar 18 03:00:03 UTC 2022


Looking at
https://stackoverflow.com/questions/54087050/java-9-serviceloader-doesnt-load-test-implementation-from-test-sources-module

It talks about the case of using ServiceLoader in tests where the services
themselves are in src/test . In this SO question Alan has the comment:

*To test TestService1 and TestService2 would require putting them into
their own test module with the appropriate provides clause. The JDK doesn't
have a --add-provides option to augment the set of services that a module
provides. There are chicken 'n egg with such an option because service
binding is part of resolution and is done long before command line options
to augment the module graph are handled.*


So my interpretation of that comment from Alan is that there is not going
to be a * --add-provides* patch option anytime soon or ever. Is that a
correct interpretation?


-------

Now for myself, I have the case where I have:
- A junit extension that uses ServiceLoader (avaje-inject-test)
- A annotation processor that will generate services for both main and test
(avaje-inject-generator)

So the Java annotation processor generates the service and so for case of
test code the service is generated into generated-test-sources. This
annotation processor supports classpath so it will also generate a
META-INF/services file and for test this file ends up in
test-classes/META-INF/services/.

The junit extension (avaje-inject-test / ONLY expected to run in test) uses
ServiceLoader and that works for classpath but not for module-path as there
is no provides clause for the generated service (so it doesn't load the
service when run in module-path). Currently I believe that there is no way
to "patch" module-path with a "--add-provides" and if I read Alan's comment
correctly there isn't likely to be such a --add-provides option
forthcoming. For this APT case these are generated services and not
expected or intended to be pulled out into another module.

Noting that this junit extension ONLY runs in test and will only EVER try
to load a service that was generated into generated-test-sources ... my
"interesting workaround" for this test specific service loading code (junit
extension), is that when the code that uses ServiceLoader finds no services
to then perform a fallback of:

read the META-INF services resources like:

    Enumeration<URL> resources =
ClassLoader.getSystemResources("META-INF/services/io.avaje.inject.test.TestModule")
... read the class names of the services from the resource content and then
use reflection to create the service instances.  So for this junit
extension this works and is maybe a decent enough approach in that the
annotation processor will generate the META-INF services file regardless of
module-path or classpath.


Have I missed something?
Is there a better approach that I should be looking at?  (Given that these
services are test specific services generated by APT and moving them into a
separate module isn't really an option)


Thanks, Rob.


More information about the jigsaw-dev mailing list