- 浏览: 103642 次
- 性别:
- 来自: 杭州
最新评论
-
whatlonelytear:
赞
java注解应用实例 - Annotation, 自定义注解, 注解类规则 -
砚台观月:
你好,例子还有吗,我想要份学习看下。提供的链接找不到了。
java网络编程之Http多线程下载应用实例 -
xianghanscce:
...
java泛型应用实例 - 自定义泛型类,方法 -
yhx1231:
...
Java反射应用实例 -
beiyeren:
写的不错啊
java注解应用实例 - Annotation, 自定义注解, 注解类规则
一直在用JDK1.5, 一直搞不清楚JDK1.6有啥特性, 就翻了翻, 发现这个Compiler API(JSR 199)动态编译Java源文件功能很有意思. Compiler API如果和反射功能一起使用, 就可以实现java源代码的动态编译并执行这些代码,有点动态语言的特征. 利用这些API普通用户也可以方便的开发自己的编译器,动态生成代码,编译并运行. 本文就通过一个动态编译并运行源文件的例子简单说明下Compile API的基本功能, 有兴趣的可以深入研究下. 本实例的完成工程代码可以从这里 下载: http://dl.iteye.com/topics/download/0807c557-4f0d-3aba-956f-9fe5c9b83962
实例中实现的功能描述:
1. 使用JavaCompiler对象的run方法编译java源代码,并在源代码所在目录生成对应的class文件
2. 使用JavaCompiler对象的getTask方法编译java源代码,并将对应的class文件生成到指定目录, 并执行所生成类中指定的"printClassName"方法
环境准备:
首先回顾一下JDK, JRE,JVM的概念和关系:
JRE是java的运行环境, 说白了有JRE才能运行java类; 同时java类是运行于虚拟机(JVM)上的, 其实虚拟机是JRE的一部分, 具体来讲,在windows上就是JRE下面的一个JVM.dll文件; JDK就是java开发工具箱, 具有编译java类的功能和运行java类的功能(自身包含了一个JRE).
知道了JDK,JRE,JVM的关系,我们就应该明白,如果要在eclipse里面使用java的编译功能必须在eclipse里面使用JDK作为Library,否则在eclipse中获取不了JavaCompiler的对象. 设置如下图:
懒得找JDK1.6,我就直接下载了个1.7装了下,然后开发工具使用MyEclipse (当然用的是免费版的 -:)).
在看我们的实例分析及源码:
首先看下run方法编译java源文件, run方法比较简单,但不能指定输出路径,监控错误信息, 调用后就在源码所在目录生成class文件,run方法的声明如下:
[plain] view plain copy
- int run(InputStream in,
- OutputStream out,
- OutputStream err,
- String... arguments)使用给定 I/O 通道和参数运行工具。按照惯例,工具如果运行成功,则返回 0;如果出现错误,则返回非 0 值。任何生成的诊断都将以某种未指定的格式写入 out 或 err。
- 参数:
- in - “标准”输入;如果为 null,则使用 System.in
- out - “标准”输出;如果为 null,则使用 System.out
- err - “标准”错误;如果为 null,则使用 System.err
- arguments - 要传递给工具的参数
- 返回:
- 如果成功,则返回 0;否则返回非 0 值
- 抛出:
- NullPointerException - 如果参数数组包含任何 null 元素。
实例源码,注释比较详细,不再解释,Compiler.java中代码片段:[java] view plain copy
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * @param sFullFileName: the java source file name with full path
- * @return bRet: true-compile successfully, false - compile unsuccessfully
- * Description: Compile java source file to java class with run method
- */
- public boolean compileFile(String sFullFileName)
- {
- boolean bRet = false ;
- // get compiler
- JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler();
- // compile the java source code by run method
- int iCompileRet = oJavaCompiler.run( null , null , null , sFullFileName);
- // set compile result
- if ( 0 == iCompileRet)
- {
- bRet = true ;
- }
- return bRet;
- }
再看下我们的getTask方法编译java源代码, 这个方法其实是构造了一个JavaCompiler.CompilationTask对象, 然后在调用这个对象的call方法, 在构造对象的过程中, 可以指定class的生成路径,监控错误信息,调用过程如下:
1) 生成JavaCompiler对象,用于构造CompilationTask对象,并编译java源代码
2) 构造DiagnosticCollector对象,用于存储诊断信息
3) 构造oStandardJavaFileManager对象,用于设置类的生成路径, 为了方便使用java反射方法,我直接将本实例中的输出路径设置为工程bin目录.实际应用中应根据场景生成道不同的目录--比如可以根据配置或者包名来做.
4) 生成源文件迭代器Iterable对象, 用于存储java源代码文件完整的路径
5) 根据上面生成的对象, 调用JavaCompiler对象的getTask构造CompilationTask对象, 并调用其call方法,编译源代码
再看下getTask方法的声明:
[plain] view plain copy
- JavaCompiler.CompilationTask getTask(Writer out,
- JavaFileManager fileManager,
- DiagnosticListener<? super JavaFileObject> diagnosticListener,
- Iterable<String> options,
- Iterable<String> classes,
- Iterable<? extends JavaFileObject> compilationUnits) 使用给定组件和参数创建编译任务的 future。该编译可能没有完成,正如 CompilationTask 接口中所述。
- 如果提供了文件管理器,则它必须能够处理 StandardLocation 中定义的所有位置。
- 参数:
- out - 用于来自编译器的其他输出的 Writer;如果为 null,则使用 System.err
- fileManager - 文件管理器;如果为 null,则使用编译器的标准文件管理器
- diagnosticListener - 诊断侦听器;如果为 null,则使用编译器的默认方法报告诊断信息
- options - 编译器选项;null 表示没有选项
- classes - 类名称(用于注释处理),null 表示没有类名称
- compilationUnits - 要编译的编译单元;null 表示没有编译单元
- 返回:
- 表示编译的对象
- 抛出:
- RuntimeException - 如果在用户提供的组件中发生不可恢复的错误。cause 为用户代码中的错误。
- IllegalArgumentException - 如果给定的任一编译单元具有不同于 source 的类型
源码清单如下,Compiler.java中代码片段:[java] view plain copy
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * @param sFullFileName: the java source file name with full path
- * @param sOutputPath: the output path of java class file
- * @return bRet: true-compile successfully, false - compile unsuccessfully
- * Description: Compile java source file to java class with getTask
- * method, it can specify the class output path and catch diagnostic
- * information
- * @throws IOException
- */
- public boolean compileFile(String sFullFileName, String sOutputPath) throws IOException
- {
- boolean bRet = false ;
- // get compiler
- JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler();
- // define the diagnostic object, which will be used to save the
- // diagnostic information
- DiagnosticCollector<JavaFileObject> oDiagnosticCollector = new DiagnosticCollector<JavaFileObject>();
- // get StandardJavaFileManager object, and set the diagnostic for the
- // object
- StandardJavaFileManager oStandardJavaFileManager = oJavaCompiler
- .getStandardFileManager(oDiagnosticCollector, null , null );
- // set class output location
- Location oLocation = StandardLocation.CLASS_OUTPUT;
- try
- {
- oStandardJavaFileManager.setLocation(oLocation, Arrays
- .asList(new File[] { new File(sOutputPath) }));
- // get JavaFileObject object, it will specify the java source file.
- Iterable<? extends JavaFileObject> oItJavaFileObject = oStandardJavaFileManager
- .getJavaFileObjectsFromFiles(Arrays.asList(new File(
- sFullFileName)));
- // compile the java source code by using CompilationTask's call
- // method
- bRet = oJavaCompiler.getTask(null , oStandardJavaFileManager,
- oDiagnosticCollector, null , null , oItJavaFileObject).call();
- //print the Diagnostic's information
- for (Diagnostic oDiagnostic : oDiagnosticCollector
- .getDiagnostics())
- {
- System.out.println("Error on line: "
- + oDiagnostic.getLineNumber() + "; URI: "
- + oDiagnostic.getSource().toString());
- }
- }
- catch (IOException e)
- {
- //exception process
- System.out.println("IO Exception: " + e);
- throw e;
- }
- finally
- {
- //close file manager
- if ( null != oStandardJavaFileManager)
- {
- oStandardJavaFileManager.close();
- }
- }
- return bRet;
- }
编译的方法就这两个简单吧, 下面我们测试下这两个方法:
首先, 声明下我们的compiler类的对象,初始化下编译的类和输出类的路径,MyMain.java中代码片段:
[plain] view plain copy
- // get compiler object
- Compiler oCompiler = new Compiler();
- // the java source file name with full path
- String sFullFileName = "E:\\myspace\\CompilerSample\\Sample.java";
- // define the output path of java class, since this demo is ran into
- // eclipse, so set it as bin
- String sOutputPath = "bin/";
测试run方法:run方法测试,控制台信息:[java] view plain copy
- // Compile java source file to java class with run method
- boolean bRet = oCompiler.compileFile(sFullFileName);
- // print result
- if (bRet)
- {
- System.out.println("Compile the source code \"" + sFullFileName
- + "\" successfully" );
- }
- else
- {
- System.out.println("Compile the source code \"" + sFullFileName
- + "\" unsuccessfully" );
- }
[plain] view plain copy
- Compile the source code "E:\myspace\CompilerSample\Sample.java" successfully
生成的类文件抓图:测试getTask方法,并利用java反射运行所生成类中的"printClassName"方法:
[java] view plain copy
- // Compile java source file, and output the class file into specified
- // path
- bRet = oCompiler.compileFile(sFullFileName, sOutputPath);
- // print result
- if (bRet)
- {
- System.out.println("Compile the source code \"" + sFullFileName
- + "\" successfully" );
- // if compile success, then execute the printClassName method of the
- // compiled class
- System.out
- .println("Execute the printClassName method of the compiled class: " );
- System.out.print(" " );
- // load the class
- Class oClass = Class.forName("Sample" );
- // new an object of sample class
- Object oObject = oClass.newInstance();
- // get object of printClassName method
- Method oMethod = oClass.getMethod("printClassName" );
- oMethod.invoke(oObject);
- }
- else
- {
- System.out.println("Compile the source code \"" + sFullFileName
- + "\" unsuccessfully" );
- }
- }
运行测试方法后,控制台打印信息:[plain] view plain copy
- Compile the source code "E:\myspace\CompilerSample\Sample.java" successfully
- Execute the printClassName method of the compiled class:
- Print the class name: Sample
生成的类文件抓图:
至此, 通过java Compiler API动态编译并运行源文件的例子就完了.
注: 转载请注明出处: http://hejiangtao.iteye.com , 用于商业得给我分成
- MyJavaExpert_V1.0-JavaCompiler应用实例.rar (11.1 KB)
- 下载次数: 165
评论
发表评论
-
<转>NetBeans 6.1 界面语言设置
2012-10-07 01:49 2349NetBeans 6.1 界面语言设置从官网下载的NetBea ... -
常见开源协议(BSD,Apache,GPL,LGPL,MIT)
2012-10-05 01:52 993BSD开源协议(original BSD license、Fr ... -
Java相对路径总结<转>
2012-03-04 17:16 10411.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或 ... -
java注解应用实例 - Annotation, 自定义注解, 注解类规则
2012-01-29 21:35 25680本文介绍了java的自定义注解及注解类编写的规则, 并通过实例 ... -
Java 序列化的高级认识--序列化反序列化, 加密存储<转>
2012-01-29 15:21 2309简介: 文章对序列化进行了更深一步的讨论,用实际的例子 ... -
java网络编程之Http多线程下载应用实例
2012-01-21 02:34 8709本demo 通过RandomAccessFile, URLC ... -
Java反射应用实例
2012-01-14 23:43 2143本文主要通过Java反射 ... -
java反射的性能问题 (转)
2012-01-14 23:36 2283很多IOC,还有框架都使用反射。特别是在通过反射调用方法的时候 ... -
java泛型应用实例 - 自定义泛型类,方法
2012-01-14 23:19 37501注: 转载请注明出处: http://hejiangtao.i ... -
泛型的效率和原始类的效率比较(转)
2012-01-14 23:16 1854用 了好久的泛型,突然听到有人说:泛型影响效率! 嘿, ... -
文本数据库的简单java实现
2012-01-14 22:58 7251注: 转载请注明出处: ...
相关推荐
在实际应用中,JavaCompiler 广泛应用于 Java 动态编译中,例如,在 Web 开发中,我们可以使用 JavaCompiler 来动态编译 Java 源代码,以便实现更加灵活的开发。 JavaCompiler 是 Java 中的一个重要的编译器接口,...
要使用JavaCompiler,首先需要获取`ToolProvider`的实例,这是访问所有工具(包括JavaCompiler)的入口点: ```java JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ``` 然后,我们需要创建一个`...
本教程将深入讲解如何实现这个过程,主要关注`java动态编译`和`将class生成jar`这两个关键步骤,同时会涉及到`JavaCompiler` API的使用。 首先,让我们了解`JavaCompiler` API。这是Java标准库中的一部分,位于`...
然后,使用MATLAB Compiler SDK将M文件编译为Java类。这一步会生成一个Java包,其中包含一个或多个Java类,这些类封装了M文件的功能。在编译过程中,你可能需要设置一些编译选项,比如输入输出参数类型,以适应Java...
总而言之,《Modern Compiler Implementation in Java, 2nd Edition》是一本详细讲解现代编译器设计和实现的权威教材,它不仅覆盖了编译器各个阶段的理论知识,而且还提供了丰富的实践项目和实例,非常适合计算机...
这些模式提供了解决常见问题的标准方案,如MVC(模型-视图-控制器)模式用于Web应用的结构组织,工厂模式和依赖注入在对象创建和管理上的应用,以及单例模式在保证类只有一个实例时的使用。 Android开发与Java紧密...
编写动态执行的Java应用程序需要一些样板代码:使用类加载器,编译错误处理等。该库的目的是使您摆脱这种开发,并使您专注于业务逻辑。 它是如何工作的? 使用该库,动态编译任务非常简单。 假设我们要编译用户动态...
在提供的压缩包文件中,"内存中编译"和"Java6内存中动态编译案例"可能包含了一些实际操作的示例代码,这些代码可能演示了如何在内存中创建源代码字符串,然后使用`JavaCompiler`编译这些源代码,而无需将它们写入...
这些案例涵盖了不同类型的应用程序,证明了trace-JIT的广泛适用性。 3. **问题讨论**:作者还讨论了基于追踪的编译过程中可能遇到的问题,特别是从编译器优化的角度出发。这些问题包括如何平衡编译时间和运行时开销...
JAC(Java ASN.1 Compiler)是用于处理ASN.1文件的工具,它提供了编译器和运行时库,使得开发者能够在Java环境中方便地进行ASN.1数据的编码和解码。在这个示例中,我们有一个eclipse工程,这意味着你可以直接在...
使用`ToolProvider`类获取`JavaCompiler`实例,这是启动编译过程的第一步。 ```java JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ``` 3. **设置标准文件描述符** `...
4. **执行编译任务**:使用`JavaCompiler`实例的`compile()`方法执行编译任务。 ```java CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compileFiles); boolean success = task...
首先,我们需要获取`ToolProvider`的实例,然后使用`getSystemJavaCompiler()`方法来获取`JavaCompiler`实例。接着,我们创建`StandardJavaFileManager`,用来管理源文件和类文件。最后,通过`JavaCompiler`的`...
在Java中,我们可以使用Java的`javax.tools.JavaCompiler`接口及其相关的API来实现这个功能。 首先,`javax.tools.JavaCompiler`是Java编译器工具接口,它是Java 6引入的一个新特性,提供了在运行时动态编译Java...
它们包含了编译Java源文件所需的所有工具,如`JavaCompiler`类,用于创建`ToolProvider`实例,该实例可以调用编译器服务。 ```java import javax.tools.*; import java.util.*; public class DynamicCompiler { ...
本资料"MATLAB应用案例:MATLAB和Java的结合使用案例"可能包含多个示例,展示了如何在MATLAB环境中调用Java代码以及在Java程序中使用MATLAB的功能。以下是关于MATLAB和Java结合使用的一些关键知识点: 1. **MATLAB...
使用`JavaCompiler.compile()`方法,传入源代码的`Iterable<JavaFileObject>`,以及之前创建的文件管理者和诊断监听器。 5. **创建源代码对象**: 对于动态编译的字符串,我们可以使用`JavaFileObject`的子类`...
Flex3 Compiler API 是一款强大的工具,它允许开发者通过Java应用程序来编译Flex应用。这种能力为那些希望利用Java的强大功能与Flex的丰富界面相结合的开发者提供了极大的灵活性。Adobe在2008年发布的《Adobe Flex 3...