如何将JDK6 ToolProvider和JavaCompiler与上下文类加载器一起使用?

我的用例是使用JDK 6中提供的ToolProvider和JavaCompiler类从java程序编译生成的源文件。源文件包含对上下文类加载器中的类的引用(它在J2EE容器中运行),但不包含在系统类加载器中。 我的理解是,默认情况下,ToolProvider将使用系统类加载器创建JavaCompiler实例。

有没有办法为JavaCompiler指定一个类加载器?

我尝试了这种方法,从IBM DeveloperWorks上的某些东西进行了修改:

FileManagerImpl fm = new FileManagerImpl(compiler.getStandardFileManager(null, null, null);); 

将FileManagerImpl定义为:

 static final class FileManagerImpl extends ForwardingJavaFileManager { public FileManagerImpl(JavaFileManager fileManager) { super(fileManager); } @Override public ClassLoader getClassLoader(JavaFileManager.Location location) { new Exception().printStackTrace(); return Thread.currentThread().getContextClassLoader(); } } 

堆栈跟踪表明它仅在注释处理期间调用一次。 我validation了要编译的源文件中引用的类不在系统类路径上,但可以从上下文类加载器中获得。

如果您知道contextclassloader已知的文件的类路径,则可以将它们传递给编译器:

  StandardJavaFileManager fileManager = compiler.getStandardFileManager(this /* diagnosticlistener */, null, null); // get compilationunits from somewhere, for instance via fileManager.getJavaFileObjectsFromFiles(List files) List options = new ArrayList(); options.add("-classpath"); StringBuilder sb = new StringBuilder(); URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); for (URL url : urlClassLoader.getURLs()) sb.append(url.getFile()).append(File.pathSeparator); options.add(sb.toString()); CompilationTask task = compiler.getTask(null, fileManager, this /* diagnosticlistener */, options, null, compilationUnits); task.call(); 

此示例假设您正在使用URLClassloader(允许您检索类路径),但如果您愿意,可以插入自己的类路径。

另一个选择是使用Commons JCI 。

你在这里问两个不同的问题。

一个是如何编译系统类路径中找不到的类。 通过将“-classpath”命令行参数传递给编译器(如Leihca首先提到的),可以很容易地解决这个问题。

第二个是如何在线程上下文类加载器上实例化ToolProvider和JavaCompiler。 在撰写本文时,这是一个未解决的问题: 从自定义类加载器使用javax.tools.ToolProvider?