【问题标题】:Using ServiceLoader within an annotation processor在注解处理器中使用 ServiceLoader
【发布时间】:2017-07-12 14:55:06
【问题描述】:

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

 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) 方法作为另一个项目的构建的一部分被调用时,它不会列出任何服务。

有没有办法让它工作?

【问题讨论】:

  • 您能再描述一下您的设置吗?你有什么项目?您的服务在哪里定义?简短的回答是,是的,应该是可能的。但是您应该弄清楚为什么 META-INF/services 文件不在您的类路径中。运行 main 方法时的类路径是什么?
  • 我正在使用 Maven 来处理项目之间的所有依赖关系,因此类路径现在有点神奇。不过,我会深入研究一下,看看是否能找到更好的答案。
  • 我发现有趣的其他事情,当我从注释处理器中加载处理器服务(如注释处理器)时,我也得到了一个空列表。而且我知道类路径在那里设置正确,因为我在注释处理器中!
  • 关于如何设置 maven 项目以及如何运行 main 方法的描述可能会有所帮助。

标签: java annotation-processing serviceloader


【解决方案1】:

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

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

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

【讨论】:

  • 感谢您的提示。节省了我的时间。
【解决方案2】:

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

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

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

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

【讨论】:

  • 我使用一个 Maven 项目。并使用java 9及其模块系统。我的注释处理器看不到我的服务。即使我使用处理器的类加载器,添加 META-INF/services,在模块信息中添加提供。 apt工作除了找不到spi。如果我从apt中加载spi,它就可以工作。所以只是apt看不到spi。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多