【问题标题】:How do I use JDK6 ToolProvider and JavaCompiler with the context classloader?如何将 JDK6 ToolProvider 和 JavaCompiler 与上下文类加载器一起使用?
【发布时间】:2010-09-21 10:17:05
【问题描述】:

我的用例是使用 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();
   }

}

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

【问题讨论】:

    标签: java javac classloader java-compiler-api


    【解决方案1】:

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

    一个是如何编译在系统类路径中找不到的类。这很容易通过将“-classpath”命令行参数传递给编译器来解决(正如 Leihca 首次提到的那样)。

    第二个是如何在线程上下文类加载器上实例化ToolProvider和JavaCompiler。在撰写本文时,这是一个未解决的问题:Using javax.tools.ToolProvider from a custom classloader?

    【讨论】:

      【解决方案2】:

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

          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(它允许您检索类路径),但您可以根据需要插入自己的类路径。

      【讨论】:

        【解决方案3】:

        另一种选择是使用Commons JCI

        【讨论】:

        • JCI 似乎不允许您传入类加载器,只允许传入路径,正如 JDK6 支持所允许的那样。
        • 您一直在寻找什么?当然可以。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 2020-05-25
        • 1970-01-01
        • 2019-01-19
        • 2021-03-24
        • 2016-10-21
        相关资源
        最近更新 更多