在注释处理器中使用ServiceLoader

时间:2017-07-12 14:55:07

标签: java annotation-processing serviceloader

是否可以在注释处理器的ServiceLoader方法中使用init(ProcessingEnvironment)

 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);
         }
     }

     ...
 }

运行main方法会生成我在META-INF / services文件中指定的服务。但是,当init(ProcessingEnvironment)方法作为另一个项目的构建的一部分被调用时,它不会列出任何服务。

有没有办法让这项工作?

2 个答案:

答案 0 :(得分:6)

问题是ServiceLoader在未指定ClassLoader时使用Thread.currentThread().getContextClassLoader(),但无法从注释处理器中查看META-INF\services文件,但可以使用main方法。

使用ServiceLoader.load(Service.class, AnnotationProcessor.class.getClassLoader())从AnnotationProcessor中正确加载服务。

(如果你知道为什么ContextClassLoader看不到META-INF\services,请随意添加我的答案)

答案 1 :(得分:0)

如果您打算在 Java模块系统上运行注释处理器:

在我看来,对于Java 11,javac编译器并不完全支持模块。我成功使用javac正确设置了--module-path进行注释处理,但是事实证明,通过ServiceLoader以同样的方式将插件加载到注释处理器中是不可能的。因此,在花了很长时间研究所有可能的编译器选项之后,我最终以一种混合方式通过模块路径加载处理器并通过类路径加载服务。

总而言之,我需要执行以下步骤(我直接在javac命令行上工作):

  1. 使用正确的module-info.javauses正确设置provided with 注释处理器和服务的声明 被加载
  2. 通过非默认ServiceLoader加载ClassLoader(请参阅bnorm的答案)
  3. 提供META-INF/services文件以加载服务
  4. 通过-classpath(或-processorpath)指定服务路径