Java_动态编译总结
不多说直接上代码:
动态编译的主类:
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;
}
Java_动态编译总结的更多相关文章
- (转载)JAVA动态编译--字节代码的操纵
在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...
- ZKWeb网站框架的动态编译的实现原理
ZKWeb网站框架是一个自主开发的网页框架,实现了动态插件和自动编译功能. ZKWeb把一个文件夹当成是一个插件,无需使用csproj或xproj等形式的项目文件管理,并且支持修改插件代码后自动重新编 ...
- java动态编译笔记
1 前言 Java的动态编译知识,真真在实际开发中并不是经常遇到.但是学习java动态编译有助于我们从更深一层次去了解java.对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知 ...
- c#动态编译并动态生成dll
/// <summary> /// 动态编译并执行代码 /// </summary> /// <param name="code">代码< ...
- Java动态编译
程序产生过程 下图展示了从源代码到可运行程序的过程,正常情况下先编译(明文源码到字节码),后执行(JVM加载字节码,获得类模板,实例化,方法使用).本文来探索下当程序已经开始执行,但在.class甚至 ...
- 重写代码生成器支持模板(多层架构,MVC),多语言c#,java;支持mysql和sqlserver,动态编译
多年前用过李天平前辈的,自己改过,后来李老师做动软了,不给源码,修改不是很方便.加上我目前需要转java方向,于是决定自己搞.到目前为止花了整整一个星期了,看看目前的成果. 最后是代码工程文件,用c# ...
- 浅谈VB.Net 程序的编译和动态编译
---恢复内容开始--- 一般,我们都是通过Visual Studio(下面简称vs)来编写和编译vb.net应用程序的,但是,不少的人并不知道vs是通过何种方式编译程序的.今天,我们就来探讨一下编译 ...
- .NET中的动态编译
代码的动态编译并执行是一个.NET平台提供给我们的很强大的工具用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码来扩展我们已有 的应用程序.这在很大程度上给我们提供了另外 ...
- C#动态编译代码,执行一个代码片段,或者从指定文件中加载某个接口的实现类
在项目进行中有时候会需要配置一些复杂的表达式,在程序运行的时候执行表达式,根据结果执行相应的操作,简单写了一个类Expression,利用.net的动态编译技术实现,代码如下: public clas ...
随机推荐
- DP专辑
今天练了一波DP.时间紧迫我就只贴代码了. 20141120 fzu2129 http://acm.fzu.edu.cn/problem.php?pid=2129 不同的子序列个数 //#pragma ...
- Git命令回顾
团队从Eclipse迁移到Android Studio之后,也从SVN迁移到Git了. 一直忙于需求迭代无暇做迁移,现在才开始做,相见恨晚,好东西,高大上,词穷. 回顾和记录一下git的一些基本操作. ...
- 报错mongoose.connection.db.collectionnames is not a function
mongoose.connection.db.collectionNames方法已经无效 建议使用mongoose.connection.db.listCollections()
- python3 爬虫
保存当前cookie到本地 import urllib.request as ur import http.cookiejar as hc url='http://www.xxxx.com/admin ...
- poj 3038
http://poj.org/problem?id=3038 这个题我是在一个关于并查集的博客中找到的,结果我就觉得这个应该是个贪心,真想不出这个与并查集有什么鬼关系,看discuss里面也都是贪心, ...
- java18
1:Map(掌握) (1)将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值. (2)Map和Collection的区别? A:Map 存储的是键值对形式的元素,键唯一,值可以重 ...
- 【python】描述符descriptor
开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...
- js学习笔记---事件代理
事件机制可以分为捕获型和冒泡型.捕获型是事件由父级元素(DOM)传递到子元素.冒泡型正好相反.事件机制默认为冒泡型.事件机制可以通过参数指定. 事件委托可以将我们绑定在document上的事件自动绑定 ...
- 参数max_allowed_packet
通信信息包是发送至MySQL服务器的单个SQL语句,或发送至客户端的单一行. 当MySQL客户端或mysqld服务器收到大于max_allowed_packet字节的信息包时,将发出“信息包过大”错误 ...
- tftp服务器的搭建
基于 红帽6的tftp搭建,当然其他系统搭建方法也大致一样 #mount /dev/cdrom /mnt/ 挂载安装光盘 不同光盘挂载用 fdisk -l 查看光盘 #rpm ...