如何在上下文类加载器中使用JDK6 ToolProvider和JavaCompiler?

6
我的使用情况是使用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<JavaFileManager> {

   public FileManagerImpl(JavaFileManager fileManager) {
      super(fileManager);
   }

   @Override
   public ClassLoader getClassLoader(JavaFileManager.Location location) {
      new Exception().printStackTrace();
      return Thread.currentThread().getContextClassLoader();
   }

}

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

3个回答

8

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

    StandardJavaFileManager fileManager = compiler.getStandardFileManager(this /* diagnosticlistener */, null, null);
// get compilationunits from somewhere, for instance via fileManager.getJavaFileObjectsFromFiles(List<file> files)
List<String> options = new ArrayList<String>();
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(它允许你检索类路径),但如果你想要的话,你可以插入自己的类路径。


1

看起来JCI不允许你传递一个类加载器进去,只能传递路径,就像JDK6的支持一样。 - Phil
你在哪里寻找?当然可以。 - tcurdt

0

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

一个是如何编译系统类路径中找不到的类。这可以通过向编译器传递“-classpath”命令行参数来轻松解决(正如Leihca首先提到的那样)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接