简体   繁体   中英

Using JavaCompiler in an OSGi Bundle

I'm in the process of refactoring a Java application to use OSGi. One feature of the application is on-the-fly Java compilation using javax.tools.JavaCompiler . In the original application this process worked by feeding the compiler the existing classpath, like so.

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

However, this won't work in an OSGi bundle since the classpath no longer contains the needed paths. In the refactored OSGi version of the application, the compiler needs access to classes that are within the same bundle as the above code, as well as classes from other bundles. How do I make the compiler aware of these classes?

I've thought of two possible solutions:

  1. Give the compiler the classloader used by the bundle containing the above code since it is aware of all the necessary classes. However, this doesn't seem like a viable solution from what I've read here and here .
  2. Build the classpath using the physical locations of the installed bundles. I've looked at org.osgi.framework.Bundle.getLocation() but I'm not sure if this would be a reliable solution. The paths I get back (at least when deploying within Eclipse) are relative and I'm not sure if they'd be safe to use across all platforms and situations.

Does option two above seem possible? Is there a better solution?

I've created a working example on GitHub .

It is not option 1 or 2, it creates a custom JavaFileManager which looks through all bundles and retrieves their resources.

Things to take into consideration:

  • It uses the JSR 199 compiler API, but it works only on the OpenJDK/Sun compiler, the Eclipse JDT compiler seems broken in this respect.
  • I've only tested on Equinox, I haven't used any equinox specific code, so it should work on other implementations.
  • It isn't optimized, so it might be slow and/or memory hungry.
  • It does register a bundle listener so it will flush its class cache when a bundle which offers a certain package resolves or unresolves
  • It is not very deterministic for split packages, I think.
  • It uses the BundleWiring API, which was introduced in OSGi 4.3, so it won't work on older OSGi implementations of OSGi (Karaf 2.x for example)

I should mention Technology Excruciation , his example helped me along tremendously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM