Module java.compiler
Package javax.tools

Interface JavaCompiler

所有超级接口:
OptionChecker, Tool

public interface JavaCompiler extends Tool, OptionChecker
从程序中调用Java编程语言编译器的接口。

编译器在编译过程中可能会生成诊断信息(例如,错误消息)。如果提供了诊断监听器,诊断信息将被提供给监听器。如果未提供监听器,则诊断信息将以未指定的格式进行格式化并写入默认输出,即System.err,除非另有规定。即使提供了诊断监听器,某些诊断信息可能不适合Diagnostic中,并将被写入默认输出。

编译器工具具有关联的标准文件管理器,这是工具本地的文件管理器(或内置的)。可以通过调用getStandardFileManager来获取标准文件管理器。

只要满足下面方法中详细说明的任何附加要求,编译器工具就必须能够与任何文件管理器一起运行。如果未提供文件管理器,则编译器工具将使用标准文件管理器,例如由getStandardFileManager返回的文件管理器。

实现此接口的实例必须符合Java语言规范并生成符合Java虚拟机规范的类文件。这些规范的版本在Tool接口中定义。此外,支持SourceVersion.RELEASE_6或更高版本的此接口实例还必须支持注解处理

编译器依赖于两个服务:诊断监听器文件管理器。尽管此包中的大多数类和接口定义了编译器(以及工具一般)的API,但接口DiagnosticListenerJavaFileManagerFileObjectJavaFileObject并不打算在应用程序中使用。相反,这些接口旨在被实现和用于为编译器提供定制服务,并因此为编译器定义了SPI。

此包中有许多类和接口旨在简化SPI的实现,以自定义编译器的行为:

StandardJavaFileManager
每个实现此接口的编译器都为操作常规文件提供了一个标准文件管理器。StandardJavaFileManager接口定义了用于从常规文件创建文件对象的附加方法。

标准文件管理器有两个目的:

  • 自定义编译器读取和写入文件的基本构建块
  • 在多个编译任务之间共享

重用文件管理器可能会减少扫描文件系统和读取jar文件的开销。尽管可能不会减少开销,但标准文件管理器必须能够处理多个连续编译,使以下示例成为推荐的编码模式:

File[] files1 = ... ; // 第一个编译任务的输入
File[] files2 = ... ; // 第二个编译任务的输入

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

Iterable<? extends JavaFileObject> compilationUnits1 =
    fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files1));
compiler.getTask(null, fileManager, null, null, null, compilationUnits1).call();

Iterable<? extends JavaFileObject> compilationUnits2 =
    fileManager.getJavaFileObjects(files2); // 使用替代方法
// 重用相同的文件管理器以允许缓存jar文件
compiler.getTask(null, fileManager, null, null, null, compilationUnits2).call();

fileManager.close();
DiagnosticCollector
用于在列表中收集诊断信息,例如:
Iterable<? extends JavaFileObject> compilationUnits = ...;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();

for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
    System.out.format("第 %d 行的错误在 %s%n",
                      diagnostic.getLineNumber(),
                      diagnostic.getSource().toUri());
}

fileManager.close();
ForwardingJavaFileManagerForwardingFileObjectForwardingJavaFileObject
无法使用子类化来覆盖标准文件管理器的行为,因为它是通过调用编译器上的方法而不是通过调用构造函数创建的。应使用转发(或委托)。这些类使得可以将大多数调用转发到给定的文件管理器或文件对象,同时允许自定义行为。例如,考虑如何记录对JavaFileManager.flush()的所有调用:
final  Logger logger = ...;
Iterable<? extends JavaFileObject> compilationUnits = ...;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) {
    @Override
    public void flush() throws IOException {
        logger.entering(StandardJavaFileManager.class.getName(), "flush");
        super.flush();
        logger.exiting(StandardJavaFileManager.class.getName(), "flush");
    }
};
compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();
SimpleJavaFileObject
此类提供了一个基本的文件对象实现,可用作创建文件对象的基本构建块。例如,以下是如何定义一个代表存储在字符串中的源代码的文件对象:
/**
 * 用于表示来自字符串的源代码的文件对象。
 */
public class JavaSourceFromString extends SimpleJavaFileObject {
    /**
     * 此“文件”的源代码。
     */
    final String code;

    /**
     * 构造一个新的JavaSourceFromString。
     * @param name 此文件对象表示的编译单元的名称
     * @param code 此文件对象表示的编译单元的源代码
     */
    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),
              Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
自1.6版本起:
1.6
参见:
  • Method Details

    • getTask

      JavaCompiler.CompilationTask getTask(Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits)
      使用给定的组件和参数创建编译任务的未来。如CompilationTask接口中所述,编译可能尚未完成。

      如果提供了文件管理器,则必须能够处理StandardLocation中定义的所有位置。

      请注意,注解处理可以处理要编译的源代码的编译单元(通过compilationUnits参数传递),以及类文件,其名称通过classes参数传递。

      参数:
      out - 用于编译器输出的Writer;如果为null,则使用System.err
      fileManager - 文件管理器;如果为null,则使用编译器的标准文件管理器
      diagnosticListener - 诊断监听器;如果为null,则使用编译器默认的诊断报告方法
      options - 编译器选项,null表示没有选项
      classes - 要由注解处理处理的类的名称,null表示没有类名
      compilationUnits - 要编译的编译单元,null表示没有编译单元
      返回:
      表示编译的对象
      抛出:
      RuntimeException - 如果用户提供的组件中发生了无法恢复的错误。 cause 将是用户代码中的错误。
      IllegalArgumentException - 如果任何选项无效,或者给定的编译单元不是类型
    • getStandardFileManager

      StandardJavaFileManager getStandardFileManager(DiagnosticListener<? super JavaFileObject> diagnosticListener, Locale locale, Charset charset)
      返回此工具的标准文件管理器实现的新实例。文件管理器将使用给定的诊断监听器生成任何非致命诊断。致命错误将使用适当的异常进行信号传递。

      如果在调用flushclose后访问标准文件管理器,标准文件管理器将自动重新打开。标准文件管理器必须可与其他工具一起使用。

      参数:
      diagnosticListener - 用于非致命诊断的诊断监听器;如果为null,则使用编译器默认的诊断报告方法
      locale - 格式化诊断时要应用的区域设置;null表示默认区域设置
      charset - 用于解码字节的字符集;如果为null,则使用平台默认值
      返回:
      标准文件管理器