模块 java.compiler

接口 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 = ... ; // input for first compilation task
File[] files2 = ... ; // input for second compilation task

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); // use alternative method
// reuse the same file manager to allow caching of jar files
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("Error on line %d in %s%n",
           diagnostic.getLineNumber(),
           diagnostic.getSource().toUri());
}

fileManager.close();
 
ForwardingJavaFileManager ForwardingFileObject ForwardingJavaFileObject
子类化不可用于覆盖标准文件管理器的行为,因为它是通过调用编译器上的方法创建的,而不是通过调用构造函数创建的。相反,应该使用转发(或委托)。这些类可以轻松地将大多数调用转发给给定的文件管理器或文件对象,同时允许自定义行为。例如,考虑如何记录对 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) {
  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
此类提供了一个基本的文件对象实现,可用作创建文件对象的构建块。例如,这里是如何定义一个文件对象,它表示存储在一个字符串中的源代码:
/**
 * A file object used to represent source coming from a string.
 */
public class JavaSourceFromString extends SimpleJavaFileObject {
  /**
   * The source code of this "file".
   */
  final String code;

  /**
   * Constructs a new JavaSourceFromString.
   * @param name the name of the compilation unit represented by this file object
   * @param code the source code for the compilation unit represented by this file object
   */
  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
参见:
  • 方法详情

    • 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 - 如果在用户提供的组件中发生不可恢复的错误。 原因 将是用户代码中的错误。
      IllegalArgumentException - 如果任何选项无效,或者如果任何给定的编译单元不是 source
    • getStandardFileManager

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

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

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