我正在重构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版本的应用程序中,编译器需要访问与上述代码在同一个包中的类,以及其他包中的类 . 如何让编译器知道这些类?
我想到了两种可能的解决方案:
-
使用已安装捆绑包的物理位置构建类路径 . 我看了
org.osgi.framework.Bundle.getLocation()
但是我不确定他们是否可以安全地在所有平台和情况下使用 .
上面的选项2似乎可能吗?有更好的解决方案吗?
1 回答
我在GitHub上创建了一个工作示例 .
它不是选项1或2,它创建一个自定义JavaFileManager,查看所有包并检索其资源 .
需要考虑的事项:
它使用JSR 199编译器API,但它仅适用于OpenJDK / Sun编译器,Eclipse JDT编译器在这方面似乎已经破解 .
I 've only tested on Equinox, I haven' t使用了任何equinox特定代码,因此它应该适用于其他实现 .
它未经过优化,因此可能很慢并且/或者内存很耗尽 .
它确实注册了一个bundle监听器,所以它会在提供某个包解析或解析的bundle时刷新它的类缓存
我觉得拆分包不是很确定 .
它使用了OSGi 4.3中引入的BundleWiring API,因此它不适用于OSGi的旧OSGi实现(例如Karaf 2.x)
我应该提一下Technology Excruciation,他的榜样帮助了我 .