Java Compiler 应用实例 _JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java Compiler 应用实例

Java Compiler 应用实例

 2012/2/9 10:18:29  hejiangtao  程序员俱乐部  我要评论(0)
  • 摘要:一直在用JDK1.5,一直搞不清楚JDK1.6有啥特性,就翻了翻,发现这个CompilerAPI(JSR199)动态编译Java源文件功能很有意思.CompilerAPI如果和反射功能一起使用,就可以实现java源代码的动态编译并执行这些代码,有点动态语言的特征.利用这些API普通用户也可以方便的开发自己的编译器,动态生成代码,编译并运行.本文就通过一个动态编译并运行源文件的例子简单说明下CompileAPI的基本功能,有兴趣的可以深入研究下.本实例的完成工程代码可以从这里下载:http
  • 标签:Java 应用 实例

一直在用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
  1. int?run(InputStream?in,??
  2. ????????OutputStream?out,??
  3. ????????OutputStream?err,??
  4. ????????String...?arguments)使用给定?I/O?通道和参数运行工具。按照惯例,工具如果运行成功,则返回?0;如果出现错误,则返回非?0?值。任何生成的诊断都将以某种未指定的格式写入?out?或?err。???
  5. ??
  6. 参数:??
  7. in?-?“标准”输入;如果为?null,则使用?System.in??
  8. out?-?“标准”输出;如果为?null,则使用?System.out??
  9. err?-?“标准”错误;如果为?null,则使用?System.err??
  10. arguments?-?要传递给工具的参数???
  11. 返回:??
  12. 如果成功,则返回?0;否则返回非?0?值???
  13. 抛出:???
  14. NullPointerException?-?如果参数数组包含任何?null?元素。??

实例源码,注释比较详细,不再解释,Compiler.java中代码片段:
[java] view plain copy
  1. /** ?
  2. ?????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com ?
  3. ?????*?@param?sFullFileName:?the?java?source?file?name?with?full?path ?
  4. ?????*?@return?bRet:?true-compile?successfully,?false?-?compile?unsuccessfully ?
  5. ?????*?Description:?Compile?java?source?file?to?java?class?with?run?method ?
  6. ?????*/ ??
  7. ????public ? boolean ?compileFile(String?sFullFileName)??
  8. ????{??
  9. ????????boolean ?bRet?=? false ;??
  10. ????????//?get?compiler ??
  11. ????????JavaCompiler?oJavaCompiler?=?ToolProvider.getSystemJavaCompiler();??
  12. ????????//?compile?the?java?source?code?by?run?method ??
  13. ????????int ?iCompileRet?=?oJavaCompiler.run( null ,? null ,? null ,?sFullFileName);??
  14. ????????//?set?compile?result ??
  15. ????????if ?( 0 ?==?iCompileRet)??
  16. ????????{??
  17. ????????????bRet?=?true ;??
  18. ????????}??
  19. ????????return ?bRet;??
  20. ????}??

再看下我们的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
  1. JavaCompiler.CompilationTask?getTask(Writer?out,??
  2. ?????????????????????????????????????JavaFileManager?fileManager,??
  3. ?????????????????????????????????????DiagnosticListener<??super?JavaFileObject>?diagnosticListener,??
  4. ?????????????????????????????????????Iterable<String>?options,??
  5. ?????????????????????????????????????Iterable<String>?classes,??
  6. ?????????????????????????????????????Iterable<??extends?JavaFileObject>?compilationUnits) 使用给定组件和参数创建编译任务的?future。该编译可能没有完成,正如?CompilationTask?接口中所述。???
  7. 如果提供了文件管理器,则它必须能够处理?StandardLocation?中定义的所有位置。???
  8. ??
  9. ??
  10. 参数:??
  11. out?-?用于来自编译器的其他输出的?Writer;如果为?null,则使用?System.err??
  12. fileManager?-?文件管理器;如果为?null,则使用编译器的标准文件管理器??
  13. diagnosticListener?-?诊断侦听器;如果为?null,则使用编译器的默认方法报告诊断信息??
  14. options?-?编译器选项;null?表示没有选项??
  15. classes?-?类名称(用于注释处理),null?表示没有类名称??
  16. compilationUnits?-?要编译的编译单元;null?表示没有编译单元???
  17. 返回:??
  18. 表示编译的对象???
  19. 抛出:???
  20. RuntimeException?-?如果在用户提供的组件中发生不可恢复的错误。cause?为用户代码中的错误。???
  21. IllegalArgumentException?-?如果给定的任一编译单元具有不同于?source?的类型??

源码清单如下,Compiler.java中代码片段: [java] view plain copy
  1. /** ?
  2. ?????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com ?
  3. ?????*?@param?sFullFileName:?the?java?source?file?name?with?full?path ?
  4. ?????*?@param?sOutputPath:?the?output?path?of?java?class?file ?
  5. ?????*?@return?bRet:?true-compile?successfully,?false?-?compile?unsuccessfully ?
  6. ?????*?Description:?Compile?java?source?file?to?java?class?with?getTask ?
  7. ?????*?????method,?it?can?specify?the?class?output?path?and?catch?diagnostic ?
  8. ?????*?????information ?
  9. ?????*?@throws?IOException? ?
  10. ?????*/ ??
  11. ????public ? boolean ?compileFile(String?sFullFileName,?String?sOutputPath)? throws ?IOException??
  12. ????{??
  13. ????????boolean ?bRet?=? false ;??
  14. ????????//?get?compiler ??
  15. ????????JavaCompiler?oJavaCompiler?=?ToolProvider.getSystemJavaCompiler();??
  16. ??
  17. ????????//?define?the?diagnostic?object,?which?will?be?used?to?save?the ??
  18. ????????//?diagnostic?information ??
  19. ????????DiagnosticCollector<JavaFileObject>?oDiagnosticCollector?=?new ?DiagnosticCollector<JavaFileObject>();??
  20. ??
  21. ????????//?get?StandardJavaFileManager?object,?and?set?the?diagnostic?for?the ??
  22. ????????//?object ??
  23. ????????StandardJavaFileManager?oStandardJavaFileManager?=?oJavaCompiler??
  24. ????????????????.getStandardFileManager(oDiagnosticCollector,?null ,? null );??
  25. ??
  26. ????????//?set?class?output?location ??
  27. ????????Location?oLocation?=?StandardLocation.CLASS_OUTPUT;??
  28. ????????try ??
  29. ????????{??
  30. ????????????oStandardJavaFileManager.setLocation(oLocation,?Arrays??
  31. ????????????????????.asList(new ?File[]?{? new ?File(sOutputPath)?}));??
  32. ??
  33. ????????????//?get?JavaFileObject?object,?it?will?specify?the?java?source?file. ??
  34. ????????????Iterable<??extends ?JavaFileObject>?oItJavaFileObject?=?oStandardJavaFileManager??
  35. ????????????????????.getJavaFileObjectsFromFiles(Arrays.asList(new ?File(??
  36. ????????????????????????????sFullFileName)));??
  37. ??
  38. ????????????//?compile?the?java?source?code?by?using?CompilationTask's?call ??
  39. ????????????//?method ??
  40. ????????????bRet?=?oJavaCompiler.getTask(null ,?oStandardJavaFileManager,??
  41. ????????????????????oDiagnosticCollector,?null ,? null ,?oItJavaFileObject).call();??
  42. ??
  43. ????????????//print?the?Diagnostic's?information ??
  44. ????????????for ?(Diagnostic?oDiagnostic?:?oDiagnosticCollector??
  45. ????????????????????.getDiagnostics())??
  46. ????????????{??
  47. ????????????????System.out.println("Error?on?line:?" ??
  48. ????????????????????????+?oDiagnostic.getLineNumber()?+?";?URI:?" ??
  49. ????????????????????????+?oDiagnostic.getSource().toString());??
  50. ????????????}??
  51. ????????}??
  52. ????????catch ?(IOException?e)??
  53. ????????{??
  54. ????????????//exception?process ??
  55. ????????????System.out.println("IO?Exception:?" ?+?e);??
  56. ????????????throw ?e;??
  57. ????????}??
  58. ????????finally ??
  59. ????????{??
  60. ????????????//close?file?manager ??
  61. ????????????if ?( null ?!=?oStandardJavaFileManager)??
  62. ????????????{??
  63. ????????????????oStandardJavaFileManager.close();??
  64. ????????????}??
  65. ????????}??
  66. ????????return ?bRet;??
  67. ????}??

编译的方法就这两个简单吧, 下面我们测试下这两个方法:

首先, 声明下我们的compiler类的对象,初始化下编译的类和输出类的路径,MyMain.java中代码片段:

[plain] view plain copy
  1. //?get?compiler?object??
  2. Compiler?oCompiler?=?new?Compiler();??
  3. //?the?java?source?file?name?with?full?path??
  4. String?sFullFileName?=?"E:\\myspace\\CompilerSample\\Sample.java";??
  5. //?define?the?output?path?of?java?class,?since?this?demo?is?ran?into??
  6. //?eclipse,?so?set?it?as?bin??
  7. String?sOutputPath?=?"bin/";??

测试run方法: [java] view plain copy
  1. //?Compile?java?source?file?to?java?class?with?run?method ??
  2. ?boolean ?bRet?=?oCompiler.compileFile(sFullFileName);??
  3. ?//?print?result ??
  4. ?if ?(bRet)??
  5. ?{??
  6. ?????System.out.println("Compile?the?source?code?\"" ?+?sFullFileName??
  7. ?????????????+?"\"?successfully" );??
  8. ?}??
  9. ?else ??
  10. ?{??
  11. ?????System.out.println("Compile?the?source?code?\"" ?+?sFullFileName??
  12. ?????????????+?"\"?unsuccessfully" );??
  13. ?}??
run方法测试,控制台信息: [plain] view plain copy
  1. Compile?the?source?code?"E:\myspace\CompilerSample\Sample.java"?successfully??

生成的类文件抓图:

测试getTask方法,并利用java反射运行所生成类中的"printClassName"方法:

[java] view plain copy
  1. //?Compile?java?source?file,?and?output?the?class?file?into?specified ??
  2. ????????//?path ??
  3. ????????bRet?=?oCompiler.compileFile(sFullFileName,?sOutputPath);??
  4. ????????//?print?result ??
  5. ????????if ?(bRet)??
  6. ????????{??
  7. ????????????System.out.println("Compile?the?source?code?\"" ?+?sFullFileName??
  8. ????????????????????+?"\"?successfully" );??
  9. ????????????//?if?compile?success,?then?execute?the?printClassName?method?of?the ??
  10. ????????????//?compiled?class ??
  11. ????????????System.out??
  12. ????????????????????.println("Execute?the?printClassName?method?of?the?compiled?class:?" );??
  13. ????????????System.out.print("??" );??
  14. ????????????//?load?the?class ??
  15. ????????????Class?oClass?=?Class.forName("Sample" );??
  16. ????????????//?new?an?object?of?sample?class ??
  17. ????????????Object?oObject?=?oClass.newInstance();??
  18. ????????????//?get?object?of?printClassName?method ??
  19. ????????????Method?oMethod?=?oClass.getMethod("printClassName" );??
  20. ????????????oMethod.invoke(oObject);??
  21. ????????}??
  22. ????????else ??
  23. ????????{??
  24. ????????????System.out.println("Compile?the?source?code?\"" ?+?sFullFileName??
  25. ????????????????????+?"\"?unsuccessfully" );??
  26. ????????}??
  27. ????}??

运行测试方法后,控制台打印信息: [plain] view plain copy
  1. Compile?the?source?code?"E:\myspace\CompilerSample\Sample.java"?successfully??
  2. Execute?the?printClassName?method?of?the?compiled?class:???
  3. ??Print?the?class?name:?Sample??

生成的类文件抓图:

至此, 通过java Compiler API动态编译并运行源文件的例子就完了.

注:?转载请注明出处: http://hejiangtao.iteye.com ,? 用于商业得给我分成大笑

  • MyJavaExpert_V1.0-JavaCompiler应用实例.rar (11.1 KB)
  • 下载次数: 14
发表评论
用户名: 匿名