在OSGi Bundle中使用JavaCompiler

are*_*dev 6 java osgi classpath classloader

我正在重构Java应用程序以使用OSGi.该应用程序的一个功能是使用即时Java编译javax.tools.JavaCompiler.在原始应用程序中,此过程通过向编译器提供现有类路径来完成,就像这样.

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
String[] options = {"-classpath", System.getProperty("java.class.path")};
DiagnosticListener<JavaFileObject> listener = new DiagnosticListener<JavaFileObject>() {...};
StandardJavaFileManager fileManager = compiler.getStandardFileManager(listener, null, null);
Iterable<? extends JavaFileObject> fileObjects = fileManager.getFileObjects(sourceFile);
CompilationTask task = compiler.getTask(null, fileManager, listener, Arrays.asList(options), null, fileObjects);
task.call();
Run Code Online (Sandbox Code Playgroud)

但是,这在OSGi包中不起作用,因为类路径不再包含所需的路径.在重构的OSGi版本的应用程序中,编译器需要访问与上述代码在同一个包中的类,以及其他包中的类.如何让编译器知道这些类?

我想到了两种可能的解决方案:

  1. 为编译器提供包含上述代码的bundle使用的类加载器,因为它知道所有必需的类.然而,这似乎不是我在这里这里读到的可行解决方案.
  2. 使用已安装的软件包的物理位置构建类路径.我看过了,org.osgi.framework.Bundle.getLocation()但我不确定这是否是一个可靠的解决方案.我得到的路径(至少在Eclipse中部署时)是相对的,我不确定它们是否可以安全地在所有平台和情况下使用.

上面的选项2似乎可能吗?有更好的解决方案吗?

Fra*_*Lee 3

我在GitHub上创建了一个工作示例。

它不是选项 1 或 2,它创建一个自定义 JavaFileManager,它会查看所有包并检索它们的资源。

需要考虑的事项:

  • 它使用 JSR 199 编译器 API,但它仅适用于 OpenJDK/Sun 编译器,Eclipse JDT 编译器在这方面似乎有问题。
  • 我只在 Equinox 上进行了测试,没有使用任何 Equinox 特定代码,因此它应该适用于其他实现。
  • 它没有经过优化,因此可能会很慢和/或占用内存。
  • 它确实注册了一个包侦听器,因此当提供某个包的包解析或取消解析时,它将刷新其类缓存
  • 我认为,对于拆分包来说,它的确定性不是很强。
  • 它使用 OSGi 4.3 中引入的 BundleWiring API,因此它不适用于 OSGi 的较旧 OSGi 实现(例如 Karaf 2.x)

我应该提到技术折磨,他的例子对我帮助很大。