Using ServiceLoader within an annotation processor

Viewed 1282

Is it possible to use ServiceLoader from within the init(ProcessingEnvironment) method of an Annotation Processor?

 interface Service {}

 class AnnotationProcessor extends AbstractProcessor {

     public static void main(String[] args) {
         ServiceLoader<Service> loader = ServiceLoader.load(Service.class);
         System.out.println("Found Services:");
         for (Service service : loader) {
             System.out.println(service);
         }
     }

     @Override
     public synchronized void init(ProcessingEnvironment env) {
         super.init(env);

         ServiceLoader<Service> loader = ServiceLoader.load(Service.class);
         System.out.println("Found Services:");
         for (Service service : loader) {
             System.out.println(service);
         }
     }

     ...
 }

Running the main method produces the services I have specified in the META-INF/services file. However, when the init(ProcessingEnvironment) method is called as part of a build of another project, it doesn't list any of the services.

Is there a way to make this work?

2 Answers

If you intend to run your annotation processor with Java module system:

It seems to me that for Java 11 the javac compiler is not completely module-aware. I succeeded to properly setup javac for annotation processing by using --module-path, but loading a plug-in via ServiceLoader into my annotation processor in the same way turned out to be impossible. Thus after a very loooong time fiddling around with all possible kind of compiler options, I ended up in a hybrid way loading the processor via module path and loading the services via class path.

All in all, the following steps were required for me (I worked directly on the javac command line):

  1. proper module-info.java setup with correct uses and provided with declarations for both, the annotation processor and the services to be loaded
  2. load ServiceLoader via non-default ClassLoader (refer to bnorm's answer)
  3. provide META-INF/services file for services to be loaded
  4. specify path to services via -classpath (or -processorpath)
Related