`
huangxx
  • 浏览: 321656 次
  • 来自: ...
社区版块
存档分类
最新评论

java 编译非文本形式的文件

阅读更多

http://www.ibm.com/developerworks/cn/java/j-lo-jse64/

 

编译非文本形式的文件

JDK 6 的编译器 API 的另外一个强大之处在于,它可以编译的源文件的形式并不局限于文本文件。JavaCompiler 类依靠文件管理服务可以编译多种形式的源文件。比如直接由内存中的字符串构造的文件,或者是从数据库中取出的文件。这种服务是由 JavaFileManager 类提供的。通常的编译过程分为以下几个步骤:

  1. 解析 javac 的参数;
  2. 在 source path 和/或 CLASSPATH 中查找源文件或者 jar 包;
  3. 处理输入,输出文件;

在这个过程中,JavaFileManager 类可以起到创建输出文件,读入并缓存输出文件的作用。由于它可以读入并缓存输入文件,这就使得读入各种形式的输入文件成为可能。JDK 提供的命令行工具,处理机制也大致相似,在未来的版本中,其它的工具处理各种形式的源文件也成为可能。为此,新的 JDK 定义了 javax.tools.FileObjectjavax.tools.JavaFileObject 接口。任何类,只要实现了这个接口,就可以被 JavaFileManager 识别。

如果要使用 JavaFileManager,就必须构造 CompilationTask。JDK 6 提供了 JavaCompiler.CompilationTask 类来封装一个编译操作。这个类可以通过:

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

方法得到。关于每个参数的含义,请参见 JDK 文档。传递不同的参数,会得到不同的 CompilationTask。通过构造这个类,一个编译过程可以被分成多步。进一步,CompilationTask 提供了 setProcessors(Iterable<? extends Processor>processors) 方法,用户可以制定处理 annotation 的处理器。图 1 展示了通过 CompilationTask 进行编译的过程:


图 1. 使用 CompilationTask 进行编译
使用 CompilationTask 进行编译

下面的例子通过构造 CompilationTask 分多步编译一组 Java 源文件。


清单 2. 构造 CompilationTask 进行编译

01 package math;

02 public class Calculator {
03     public int multiply(int multiplicand, int multiplier) {
04         return multiplicand * multiplier;
05     }
06 }

07 package compile;
08 import javax.tools.*;
09 import java.io.FileOutputStream;
10 import java.util.Arrays;
11 public class Compiler {
12   public static void main(String[] args) throws Exception{
13     String fullQuanlifiedFileName = "math" + java.io.File.separator +"Calculator.java";
14     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
15     StandardJavaFileManager fileManager  =
           compiler.getStandardFileManager(null, null, null);

16     Iterable<? extends JavaFileObject> files =
             fileManager.getJavaFileObjectsFromStrings(
             Arrays.asList(fullQuanlifiedFileName));
17     JavaCompiler.CompilationTask task = compiler.getTask(
             null, fileManager, null, null, null, files);

18     Boolean result = task.call();
19     if( result == true ) {
20       System.out.println("Succeeded");
21     }
22   }
23 }
   

以上是第一步,通过构造一个 CompilationTask 编译了一个 Java 文件。14-17 行实现了主要逻辑。第 14 行,首先取得一个编译器对象。由于仅仅需要编译普通文件,因此第 15 行中通过编译器对象取得了一个标准文件管理器。16 行,将需要编译的文件构造成了一个 Iterable 对象。最后将文件管理器和 Iterable 对象传递给 JavaCompilergetTask 方法,取得了 JavaCompiler.CompilationTask 对象。

接下来第二步,开发者希望生成 Calculator 的一个测试类,而不是手工编写。使用 compiler API,可以将内存中的一段字符串,编译成一个 CLASS 文件。


清单 3. 定制 JavaFileObject 对象

01 package math;
02 import java.net.URI;
03 public class StringObject extends SimpleJavaFileObject{
04     private String contents = null;
05     public StringObject(String className, String contents) throws Exception{
06         super(new URI(className), Kind.SOURCE);
07         this.contents = contents;
08     }

09     public CharSequence getCharContent(boolean ignoreEncodingErrors) 
             throws IOException {
10         return contents;
11     }
12 }
   

SimpleJavaFileObjectJavaFileObject 的子类,它提供了默认的实现。继承 SimpleJavaObject 之后,只需要实现 getCharContent 方法。如 清单 3 中的 9-11 行所示。接下来,在内存中构造 Calculator 的测试类 CalculatorTest,并将代表该类的字符串放置到 StringObject 中,传递给 JavaCompilergetTask 方法。清单 4 展现了这些步骤。


清单 4. 编译非文本形式的源文件

01 package math;
02 import javax.tools.*;
03 import java.io.FileOutputStream;
04 import java.util.Arrays;
05 public class AdvancedCompiler {
06   public static void main(String[] args) throws Exception{

07     // Steps used to compile Calculator
08     // Steps used to compile StringObject

09     // construct CalculatorTest in memory
10     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
11     StandardJavaFileManager fileManager  =
           compiler.getStandardFileManager(null, null, null);
12         JavaFileObject file = constructTestor();
13         Iterable<? extends JavaFileObject> files = Arrays.asList(file);
14         JavaCompiler.CompilationTask task = compiler.getTask (
                 null, fileManager, null, null, null, files);

15         Boolean result = task.call();
16         if( result == true ) {
17           System.out.println("Succeeded");
18         }
19   }

20   private static SimpleJavaFileObject constructTestor() {
21     StringBuilder contents = new StringBuilder(
           "package math;" +
           "class CalculatorTest {\n" +
      	   "  public void testMultiply() {\n" +
		   "    Calculator c = new Calculator();\n" +
		   "    System.out.println(c.multiply(2, 4));\n" +
		   "  }\n" +
		   "  public static void main(String[] args) {\n" +
		   "    CalculatorTest ct = new CalculatorTest();\n" +
		   "    ct.testMultiply();\n" +
		   "  }\n" +
		   "}\n");
22      StringObject so = null;
23      try {
24        so = new StringObject("math.CalculatorTest", contents.toString());
25      } catch(Exception exception) {
26        exception.printStackTrace();
27      }
28      return so;
29    }
30 }

实现逻辑和 清单 2 相似。不同的是在 20-30 行,程序在内存中构造了 CalculatorTest 类,并且通过 StringObject 的构造函数,将内存中的字符串,转换成了 JavaFileObject 对象。

分享到:
评论
2 楼 郭玉成 2013-04-23  
你好, 我已经找到原因了!
1 楼 郭玉成 2013-04-23  
你好! 我在编译一个项目的时候,我是逐个文件编译的,但是当有的类导入其他包中的类而且被导入包中的类还没用编译,这样就会造成:“找不到符号
符号: 类 JavaCompilerWorker
位置: 软件包 parser
import parser.JavaCompilerWorker;”
这个错误! 有什么办法能更好的动态编译吗?

相关推荐

    查看java编译后的class文件的反编译工具.rar

    3. 生成源代码表示:将字节码转换为接近Java源代码的文本形式。 4. 显示结果:在用户界面中展示反编译的源代码,便于阅读和分析。 值得注意的是,由于反编译可能会丢失一些元数据,如注释和原始源代码的格式,所以...

    java反编译工具,文件比较工具

    Java反编译工具主要用于将已编译的Java字节码(.class文件)转换回可读的源代码格式,这对于理解第三方库的功能、调试问题或者恢复丢失的源代码非常有用。尽管反编译不总是能完全还原原始的源代码,但它们可以提供一...

    java反编译工具

    这类工具能够将已经编译过的Java类文件转换回其原始的Java源代码形式,以便于理解、学习或者调试。在Java编程环境中,源代码通常被编译成字节码,这是Java虚拟机(JVM)可以执行的语言。然而,在某些情况下,我们...

    Java反编译工具,将class文件反编译成Java文件

    Java反编译是编程领域中一个重要的技术环节,它允许开发者查看和理解已经编译成字节码(.class文件)的Java程序的原始源代码。这种能力在多种情况下非常有用,例如,当我们需要分析开源软件的实现细节,或者当我们...

    java反编译文件 java反编译文件

    Java反编译是将已编译的字节码文件(.class)转换回源代码(.java)的过程,这对于理解库或框架的工作原理、逆向工程、学习代码或者在丢失源代码的情况下恢复源代码非常有用。Java的字节码是平台无关的,这使得Java...

    Java class文件反编译工具集

    Java class文件是Java程序编译后的二进制代码,它包含了类、方法、变量等信息。但是,由于class文件是以机器可读的形式存在,对于人类来说并不直观。这时,我们就需要借助于反编译工具来将class文件转换回源代码...

    安卓、Java反编译工具

    2. **JAD**:Java反汇编器JAD可以将`.class`文件转换为更接近Java源代码的文本格式。虽然不如JD-GUI直观,但更适合进行深度分析。 3. **Apktool**:这是一款专门针对Android应用的反编译工具,它可以解包APK文件,...

    java编译文件反编译工具.zip

    Java编译文件反编译工具,正如其名,是一种专门用于将已编译的Java字节码(.class文件)转换回源代码(.java文件)的软件或插件。在Java开发过程中,反编译工具能够帮助开发者理解他人的代码实现、调试问题或者在...

    java反编译插件 方便查看class文件

    在命令行中,你可以使用类似`jad -c MyClassName.class &gt; MyClassName.java`的命令,这将会把`MyClassName.class`反编译为`MyClassName.java`的文本文件。如果你需要处理整个目录,可以使用通配符或者递归操作。 ...

    java class文件反编译工具

    Java Class文件是Java程序编译后的二进制代码,它包含了执行字节码,用于JVM(Java虚拟机)运行。然而,这些字节码对于人类来说并不直观,因此有时我们需要将其转换回可读的源代码,即进行反编译。这个过程有助于...

    JAVA反编译详细步骤

    Java反编译是将已编译的字节码(.class文件)转换回源代码的过程,这对于理解已封装的库或研究代码行为非常有用。在这个详细的教程中,我们将深入探讨几种常用的Java反编译工具,以及如何使用它们来增强你的Java开发...

    java反编译软件java反编译软件java反编译软件

    Java反编译软件是开发者和逆向工程人员用于查看Java字节码的工具,它能够将已编译的.class文件转换回源代码形式。在Java编程中,源代码被编译成字节码,这是一种平台无关的中间表示,使得Java程序能够在任何支持Java...

    Java反编译工具(将class文件转为Java文件,免安装)

    当我们只有.class文件而没有原始的.java源代码时,反编译可以帮助我们理解代码的工作原理,虽然转换回来的代码可能无法完全匹配原始的源代码格式和注释。 标题提到的“Java反编译工具”是一种无需安装即可使用的...

    javadecompiler java反编译工具

    Java反编译器是开发人员在处理Java字节码时常用的一种工具,它能够将已编译的Java类文件转换回源代码形式,以便于理解、学习或调试。标题中的"javadecompiler"指的是这类工具,而"java反编译工具"进一步明确了它的...

    Java反编译工具

    这些字节码文件并不直接包含源代码的文本形式,而是包含了操作码和类结构信息。反编译工具的任务就是从这些字节码中重构出接近原始的源代码。 常用的Java反编译工具有很多,其中最知名的可能是JD-GUI和JD-Core。JD-...

    java代码快捷编译运行工具

    首先,我们需要编写源代码,这些源代码通常以.java文件的形式存在。例如,一个简单的"Hello, World!"程序会包含一个名为"HelloWorld.java"的文件,其中包含如下内容: ```java public class HelloWorld { public ...

    java反编译小工具

    5. **输出格式**:可能提供将反编译结果导出为文本文件或直接集成到IDE的功能。 在实际应用中,反编译工具可以帮助开发者进行以下任务: - **逆向工程**:了解第三方库的内部工作原理,特别是没有源代码的情况下。...

    java 反编译工具

    当原始源代码丢失或未提供时,反编译工具就派上了用场,它能将.class文件转换回接近原始的Java源代码形式。 本文将详细介绍Java反编译工具的功能、工作原理以及如何使用DJ Java Decompiler这一特定版本的反编译工具...

Global site tag (gtag.js) - Google Analytics