java编译器API——使用编译工具

【0】README

0.1)以下内容转自: http://suntips.iteye.com/blog/69002

0.2)for basic java compiler API, please visit  http://blog.csdn.net/pacosonswjtu/article/details/50718494


1)当你需要更好的处理这些结果时,你可以使用第二种方法来访问编译器. 

更特别的是,这第二种方式允许开发者将编译输出结果用一种更有意义的方式表现出来,而不是简单的那种送往stdeer的错误文本. 利用 StandardJavaFileManager 类我们有这种更好的途径使用编译器. 这个文件管理器提供了一种方式,用来处理普通文件的输入输出操作. 它同时利用 DiagnosticListener 实例来报告调试信息. 你需要使用的 DiagnosticCollector 类其实是监听器的一种实现.

2)在搞清楚你需要编译什么之前,你需要一个文件管理器. 生成一个管理器基本上需要两步:  创建一个DiagnosticCollector 和 使用 JavaCompiler 的 getStandardFileManager() 方法获得一个文件管理器. 把DiagnosticListener 对象传入 getStandardFileManager() 方法中. 这个监听器可以报告一些非致命的问题,到后来你可以选择性的通过把它传入 getTask() 方法来和编译器共享. 

DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, aLocale, aCharset);

3)你也可以往这个调用里传入一个 null 值的诊断器,但这样也就等于用以前的编译器方法了.

3.1)在详细查看 StandardJavaFileManager 之前 ,编译过程涉及到 JavaCompiler 的一个方法叫做 getTask() . 它有六个参数,返回一个叫做 CompilationTask  内部类的实例: 

JavaCompiler.CompilationTask getTask( 
    Writer out, 
    JavaFileManager fileManager, 
    DiagnosticListener<? super JavaFileObject> diagnosticListener, 
    Iterable<String> options, 
    Iterable<String> classes, 
    Iterable<? extends JavaFileObject> compilationUnits)

3.2)缺省情况下,大部分它的参数可以是 null.

* out: System.err 
* fileManager: compiler's standard file manager
* diagnosticListener: compiler's default behavior
* options: no command-line options to compiler
* classes: no class names for annotation processing

3.3)最后一个参数 compilationUnits 却是不能够为null ,因为它是你要去编译的东西. 它把我们又带回了StandardJavaFileManager 类.注意这个参数类型: Iterable<? extends JavaFileObject> .  StandardJavaFileManager 有两个方法返回这样的结果. 你可以使用一个文件对象的List或者String 对象的List,用它们来表示文件名:  

Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) 
Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings( Iterable<String> names)

3.4)并不仅仅 List ,实际上,任何一个能够标识需要编译的内容的集合的 Iterable 都可以.  List 出现在这里只是因为它容易生成: 

String[] filenames = ...; 
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(filenames)); 

3.5)现在你有了编译源文件的所有的必要的信息. 从 getTask( ) 返回的 JavaCompiler.CompilationTask  实现了Callable .接口 这样,想让任务开始就去调用call()方法. 

JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
Boolean success = task.call(); 

4)如果没有编译警告和错误,这个call() 方法会编译所有的 compilationUnits 变量指定的文件,以及有依赖关系的可编译的文件. 

想要知道是否所有的都成功了,去查看一下返回的 Boolean 值. 只有当所有的编译单元都执行成功了,这个 call() 方法才返回 Boolean.TRUE  . 一旦有任何错误,这个方法就会返回 Boolean.FALSE .

在展示运行这个例子之前,让我们添加最后一个东西,DiagnosticListener , 或者更确切的说, DiagnosticCollector .的实现类.把这个监听器当作getTask()的第三个参数传递进去,你就可以在编译之后进行一些调式信息的查询了. 

for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 
  System.console().printf( 
      "Code: %s%n" + 
      "Kind: %s%n" + 
      "Position: %s%n" + 
      "Start Position: %s%n" + 
      "End Position: %s%n" + 
      "Source: %s%n" + 
      "Message:  %s%n", 
      diagnostic.getCode(), diagnostic.getKind(), 
      diagnostic.getPosition(), diagnostic.getStartPosition(), 
      diagnostic.getEndPosition(), diagnostic.getSource(), 
      diagnostic.getMessage(null)); 
}

5)在最后,你应该调用管理器的close() 方法.

6)把所有的放在一起,就得到的了下面的程序,让我们重新编译Hello(StandardJavaFileManagerTest)类.  

package com.corejava.chapter10_2;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Locale;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class AdvancedJavaCompiler
{
 public static void main(String[] args) throws IOException
 {
  JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 返回java 编译器
  // DiagnosticCollector 是监听器的一种实现
  DiagnosticCollector<JavaFileObject>  diagnostics = new DiagnosticCollector<>(); 
  // java 文件管理器
  StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, Locale.CHINA, Charset.forName("UTF-8")); 
  /* Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) 
     Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) */
  
  // 所要编译的源文件
  Iterable<? extends JavaFileObject> compilationUnits = manager.getJavaFileObjects("com/corejava/chapter10_2/StandardJavaFileManagerTest.java");
  CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, compilationUnits);
  // 如果没有编译警告和错误,这个call() 方法会编译所有的 compilationUnits 变量指定的文件,以及有依赖关系的可编译的文件.
  Boolean suc = task.call();
  
  /* 只有当所有的编译单元都执行成功了,这个 call() 方法才返回 Boolean.TRUE  . 一旦有任何错误,这个方法就会返回 Boolean.FALSE .
   * 在展示运行这个例子之前,让我们添加最后一个东西,DiagnosticListener , 或者更确切的说,  DiagnosticCollector .的实现类.
   * 把这个监听器当作getTask()的第三个参数传递进去,你就可以在编译之后进行一些调式信息的查询了. */
  for(Diagnostic diagnostic : diagnostics.getDiagnostics())
  {
   System.console().printf(
    "Code: %s%n" + 
          "Kind: %s%n" + 
          "Position: %s%n" + 
          "Start Position: %s%n" + 
          "End Position: %s%n" + 
          "Source: %s%n" + 
          "Message:  %s%n", 
          diagnostic.getCode(), diagnostic.getKind(), 
          diagnostic.getPosition(), diagnostic.getStartPosition(), 
          diagnostic.getEndPosition(), diagnostic.getSource(), 
          diagnostic.getMessage(null));
  }
  manager.close();
  System.out.println("success : " + suc);
 }
}


7)然而,如果你把 println  方法改成书写错误的 pritnln 方法,当你运行时你会得到下面的信息: 

E:\bench-cluster\cloud-data-preprocess\CoreJavaAdvanced\src>java com.corejava.chapter10_2.AdvancedJa 
vaCompiler 
Code: compiler.err.cant.resolve.location.args 
Kind: ERROR 
Position: 139 
Start Position: 129 
End Position: 147 
Source: RegularFileObject[com\corejava\chapter10_2\StandardJavaFileManagerTest.java] 
Message:  找不到符号 
  符号:   方法 printnl(java.lang.String) 
  位置: 类型为java.io.PrintStream的变量 out 
success : false


Attention) for source code about instances above, please visit  https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter10/10_2

使用Compiler API,你可以实现比在这篇简要的提示介绍的更多的事情. 例如,你可以控制输入输出的目录或者在集成编译器里高亮一些编译错误. 现在,向 Java Compiler API表示感谢,你可以使用标准API了. For more information on the Java Compiler API and JSR 199, see the JSR 199 specification.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值