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

发布于 2024-07-08 06:04:16 字数 909 浏览 11 评论 0原文

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

}

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

My usage case is compiling generated source files from a java program using the ToolProvider and JavaCompiler classes provided in JDK 6. The source files contain references to classes in the context classloader (it runs in a J2EE container), but not in the system classloader. My understanding is that by default the ToolProvider will create the JavaCompiler instance with the system classloader.

Is there a way to specify a classloader for JavaCompiler to use?

I tried this approach, modified from something on IBM DeveloperWorks:

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

with FileManagerImpl defined as:

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

}

The stacktrace indicates it's only called once during annotation processing. I verified the class referenced in the source file to be compiled is not on the system classpath but is available from the context classloader.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

仙女山的月亮 2024-07-15 06:04:16

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

If you know the classpath to the files that are known to the contextclassloader you can pass them to the compiler:

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

This example assumes you're using a URLClassloader (which allows you to retrieve the classpath) but you could insert your own classpath if you wanted to.

彩虹直至黑白 2024-07-15 06:04:16

另一种选择是使用 Commons JCI

Another option is to use Commons JCI.

梦晓ヶ微光ヅ倾城 2024-07-15 06:04:16

您在这里问两个单独的问题。

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

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

You're asking two separate questions here.

One is how to compile classes not found in the system classpath. This is easily solved by passing the "-classpath" command-line argument to the compiler (as first mentioned by Leihca).

The second is how to instantiate ToolProvider and JavaCompiler on the thread context classloader. At the time of this writing, this is an unsolved question: Using javax.tools.ToolProvider from a custom classloader?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文