3

是否可以在注释处理器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)方法作为另一个项目的构建的一部分被调用时,它不会列出任何服务。

有没有办法使这项工作?

4

2 回答 2

9

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

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

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

于 2017-07-14T13:14:29.973 回答
0

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

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

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

  1. 正确module-info.java设置注释处理器usesprovided with 要加载的服务的正确声明
  2. ServiceLoader通过非默认加载ClassLoader(请参阅 bnorm 的答案)
  3. META-INF/services为要加载的服务提供文件
  4. -classpath通过(或-processorpath)指定服务路径
于 2019-02-06T14:20:04.070 回答