不多说直接上代码:
动态编译的主类:
package com.lkb.autoCode.util; import com.lkb.autoCode.constant.AutoCodeConstant; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.tools.*; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * AutoCompiler 动态编译器 * * @author Lilin * @date 2016/5/18 */ public class AutoCompiler { private static final Log log = LogFactory.getLog(AutoCompiler.class); /** * Description: Compile java source file to java class with run method * * @param fullFileName the java source file name with full path * @return true-compile successfully, false - compile unsuccessfully */ public static boolean compileFile(String fullFileName) { boolean bRet = false; // get compiler JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler(); // compile the java source code by run method int iCompileRet = oJavaCompiler.run(null, null, null, fullFileName); // set compile result if (0 == iCompileRet) { bRet = true; } return bRet; } /** * Description: Compile java source file to java class with getTask * method, it can specify the class output path and catch diagnostic * information * * @param fullFileName the java source file name with full path * @param outputPath the output path of java class file * @return true-compile successfully, false - compile unsuccessfully * @throws IOException */ public static boolean compileFile(String fullFileName, String outputPath) { System.out.println("源文件路径:" + fullFileName); System.out.println("输入路径:" + outputPath); boolean bRet = false; // get compiler // TODO 当运行环境是JRE是无法直接ToolProvider.getSystemJavaCompiler();这么获取 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 JavaFileManager.Location oLocation = StandardLocation.CLASS_OUTPUT; try { File outputFile = new File(outputPath); if (!outputFile.exists()) { outputFile.mkdir(); } List<File> dependencies = new ArrayList<File>(); // 加载依赖的jar文件 dependencies.addAll(getJarFiles(AutoCodeConstant.JARS_PATH)); // 加载依赖的class文件 dependencies.add(new File(AutoCodeConstant.BASE_PATH)); oStandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, dependencies); oStandardJavaFileManager.setLocation(oLocation, Arrays .asList(new File[]{outputFile})); File sourceFile = new File(fullFileName); // get JavaFileObject object, it will specify the java source file. Iterable<? extends JavaFileObject> oItJavaFileObject = oStandardJavaFileManager .getJavaFileObjectsFromFiles(Arrays.asList(sourceFile)); // -g 生成所有调试信息 // -g:none 不生成任何调试信息 // -g:{lines,vars,source} 只生成某些调试信息 // -nowarn 不生成任何警告 // -verbose 输出有关编译器正在执行的操作的消息 // -deprecation 输出使用已过时的 API 的源位置 // -classpath <路径> 指定查找用户类文件的位置 // -cp <路径> 指定查找用户类文件的位置 // -sourcepath <路径> 指定查找输入源文件的位置 // -bootclasspath <路径> 覆盖引导类文件的位置 // -extdirs <目录> 覆盖安装的扩展目录的位置 // -endorseddirs <目录> 覆盖签名的标准路径的位置 // -d <目录> 指定存放生成的类文件的位置 // -encoding <编码> 指定源文件使用的字符编码 // -source <版本> 提供与指定版本的源兼容性 // -target <版本> 生成特定 VM 版本的类文件 // -version 版本信息 // -help 输出标准选项的提要 // -X 输出非标准选项的提要 // -J<标志> 直接将 <标志> 传递给运行时系统 // 编译选项,将编译产生的类文件放在当前目录下 //Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING, "-classpath", getJarFiles(AutoCodeConstant.JARS_PATH)); Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING); // compile the java source code by using CompilationTask‘s call method bRet = oJavaCompiler.getTask(null, oStandardJavaFileManager, oDiagnosticCollector, options, null, oItJavaFileObject).call(); //print the Diagnostic‘s information for (Diagnostic oDiagnostic : oDiagnosticCollector .getDiagnostics()) { // log.info("Error on line: " // + oDiagnostic.getLineNumber() + "; URI: " // + oDiagnostic.getSource().toString()); System.out.printf( "Code: %s%n" + "Kind: %s%n" + "Position: %s%n" + "Start Position: %s%n" + "End Position: %s%n" + "Source: %s%n" + "Message: %s%n", oDiagnostic.getCode(), oDiagnostic.getKind(), oDiagnostic.getPosition(), oDiagnostic.getStartPosition(), oDiagnostic.getEndPosition(), oDiagnostic.getSource(), oDiagnostic.getMessage(null)); } } catch (IOException e) { log.error("动态编译出现异常", e); } finally { //close file manager if (null != oStandardJavaFileManager) { try { oStandardJavaFileManager.close(); } catch (IOException e) { e.printStackTrace(); log.error("动态编译关闭文件管理器出现异常", e); } } } return bRet; } /** * 查找该目录下的所有的jar文件 * * @param jarPath * @throws Exception */ private static List<File> getJarFiles(String jarPath) { final List<File> dependencyJars = new ArrayList<File>(); File sourceFile = new File(jarPath); if (sourceFile.exists()) {// 文件或者目录必须存在 if (sourceFile.isDirectory()) {// 若file对象为目录 // 得到该目录下以.java结尾的文件或者目录 File[] childrenFiles = sourceFile.listFiles(new FileFilter() { public boolean accept(File pathname) { if (pathname.isDirectory()) { return true; } else { String name = pathname.getName(); if (name.endsWith(".jar") ? true : false) { //jars[0] = jars[0] + pathname.getPath() + ";"; dependencyJars.add(pathname); return true; } return false; } } }); } } return dependencyJars; } }
辅助类:
package com.lkb.autoCode.constant; /** * AutoCodeConstant * * @author Lilin * @date 2016/5/18 */ public class AutoCodeConstant { /** * 登录模板名称 */ public static String LOGIN_TEMPLATE_FTL = "LoginClientTemplate.ftl"; /** * 项目根路径 */ public final static String BASE_PATH = AutoCodeConstant.class.getResource("/").toString().replaceAll("^file:/", ""); /** * Jar包所在目录 */ public final static String JARS_PATH = BASE_PATH.replace("classes","lib"); /** * 模板根路径 */ public final static String BASE_TEMPLATE_PATH = BASE_PATH + "template"; /** * client目录 */ public final static String LOCAL_CLIENT_BASE_PATH = "src/main/java/com/lkb/sb/client/"; /** * client目录 */ public final static String CLIENT_BASE_PATH = "com/lkb/sb/client/"; /** * client类名后缀 */ public final static String LOGIN_CLIENT_SUFFIX = "LoginClient.java"; /** * 默认编译输出路径 */ public final static String DEFULT_OUTPUT_PATH = "/"; /** * 编码格式 */ public final static String CONTENT_ENCODING = "UTF-8"; }
开发背景:需求是根据代码模板动态生成java代码,并动态编译
开发过程中遇到的阻塞:模板代码中有依赖别的class文件和jar文件无法加载的问题
解决方法:
// 加载依赖的jar文件 dependencies.addAll(getJarFiles("jar文件的根路径")); // 加载依赖的class文件 dependencies.add(new File("class文件的根路径")); /** * 查找该目录下的所有的jar文件 * * @param jarPath * @throws Exception */ private static List<File> getJarFiles(String jarPath) { final List<File> dependencyJars = new ArrayList<File>(); File sourceFile = new File(jarPath); if (sourceFile.exists()) {// 文件或者目录必须存在 if (sourceFile.isDirectory()) {// 若file对象为目录 // 得到该目录下以.java结尾的文件或者目录 File[] childrenFiles = sourceFile.listFiles(new FileFilter() { public boolean accept(File pathname) { if (pathname.isDirectory()) { return true; } else { String name = pathname.getName(); if (name.endsWith(".jar") ? true : false) { //jars[0] = jars[0] + pathname.getPath() + ";"; dependencyJars.add(pathname); return true; } return false; } } }); } } return dependencyJars; }
时间: 2024-10-09 17:16:11