在 OSGi Bundle 中使用 JavaCompiler

Posted

技术标签:

【中文标题】在 OSGi Bundle 中使用 JavaCompiler【英文标题】:Using JavaCompiler in an OSGi Bundle 【发布时间】:2011-09-21 09:35:34 【问题描述】:

我正在重构 Java 应用程序以使用 OSGi。该应用程序的一项功能是使用javax.tools.JavaCompiler 进行动态Java 编译。在原始应用程序中,这个过程通过向编译器提供现有的类路径来工作,就像这样。

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

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

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

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

上面的选项二似乎可行吗?有没有更好的解决方案?

【问题讨论】:

另一个注意事项:我看到了一种方法here 似乎可行,但它取决于内部 JDT 类。根据我的阅读,这不是一个好习惯。 【参考方案1】:

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

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

需要考虑的事项:

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

我应该提到Technology Excruciation,他的榜样对我帮助很大。

【讨论】:

以上是关于在 OSGi Bundle 中使用 JavaCompiler的主要内容,如果未能解决你的问题,请参考以下文章

让 OSGi 服务使用最新版本的 bundle,即使安装了多个 bundle 版本

如何在java中使用来自另一个bundle的OSGI引用

OSGI Bundle 中的 Android Activity

使用 maven-bundle-plugin 安装 OSGi 依赖项

即使所需的 JAR 在 Bundle-classpath 中,OSGI 类也不可见

OSGI 包中 Bundle-Classpath 的预期用例是啥