Search code examples
javaannotation-processingserviceloader

Using ServiceLoader within an annotation processor


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?


Solution

  • The problem is ServiceLoader uses Thread.currentThread().getContextClassLoader() when a ClassLoader is not specified which cannot see the META-INF\services files from within an Annotation Processor but can from the main method.

    Using ServiceLoader.load(Service.class, AnnotationProcessor.class.getClassLoader()) properly loads the services from within AnnotationProcessor.

    (Feel free to add to my answer if you know why ContextClassLoader cannot see META-INF\services)