一、使用 javax.tools 包下面的ToolProvider.getSystemJavaCompiler() 方法,具体如下:
String path = "src/main/resources/templates";
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
int run = javaCompiler.run(null, null, null, "-d", path, "src/main/resources/templates/Hello.java");
System.out.println(run);
run 方法中前三个参数为系统的输入、输出以及异常流,可直接设置为null,重点是后面三个,“-d” 指定编译到某文件夹下面,后可跟盘符,和-D有的区别在于-D是设置系统参数的,-d是设置指定文件目录的;第五个参数为指定编译后的class文件存放的位置(可跟盘符),第六个参数就是要编译的java文件路劲,注意,按照上述方法编译是不会出错的,如果报异常为:无效标记(后面是路劲),说明没有指定的文件夹,或者不存在该文件夹路劲即可;最后run返回的值为0时,说明编译成功。
另外看了好些个版本的,参数都不一样,比如:
compiler.run(null, null, null,"-encoding","UTF-8","-classpath", "src/main/resources/templates/","src/main/resources/templates/Hello.java");
"-encoding","UTF-8","-classpath" ,其实这种方式和上面的都一样,-classpath是指定的编译后的class文件存放位置为当前java文件所在的位置,和上面的-d一个作用,但-d时存放在指定目录下, 这两种方式对于比如说有两个类(相互引用)、或者有其中一个类引用了另一个类,编译都会失败。
另外还有一种方式是使用Runtime执行javac命令的方式来编译Java代码如下:
String jarAbsolutePath = "src/main/resources/static/";//指定编译后的存放的class文件位置
String javaAbsolutePath = "src/main/resources/templates/Student.java";//需要编译的java文件
Process process = Runtime.getRuntime().exec("javac -classpath " + jarAbsolutePath + " " + javaAbsolutePath);//-classpath位置可用-d来代替
try {
InputStream errorStream = process.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
int exitVal = process.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (InterruptedException e) {
e.printStackTrace();
}
上述编译成功后会打印:Process exitValue: 0
如有乱码或者打印多行,说明编译失败,请仔细看看路劲是否正确。
但是这两中方式最终都不能解决方才说的两个类的引用编译问题,最后通过查阅多个资料,看到一种编译方式非常好用,直接代码:
//递归获取指定编译目录下的所有java文件并放入文件集合中
public static void compiler(File file, String targetPath, List<File> sourceFiles) {
File targetDir = new File(targetPath);
if (!targetDir.exists()) {
targetDir.mkdirs();
}
if (file != null && file.exists()) {
File[] listFiles = file.listFiles();
if (null == listFiles || listFiles.length == 0) {
return;
}
for (File file2 : listFiles) {
if (file2.isDirectory()) {
compiler(file2, targetPath, sourceFiles);
} else {
if (file2.getName().endsWith(".java")) {
try {
sourceFiles.add(file2);
} catch (Exception e) {
System.out.println("888888");// TODO: handle exception
}
}
}
}
}
}
//编译java文件
public static boolean compilerJavaFile(List<File> sourceFile, String targerPath) throws IOException{
boolean flag = false;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);
Iterable<? extends JavaFileObject> javaFileObjectsFromFiles = fileManager
.getJavaFileObjectsFromFiles(sourceFile);
Iterable<String> options = Arrays.asList("-d", "src/main/resources/static/");
flag = compiler.getTask(null, fileManager, diagnosticCollector, options, null, javaFileObjectsFromFiles).call();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnosticCollector.getDiagnostics()) {
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",
diagnostic.getCode(), diagnostic.getKind(), diagnostic.getPosition(), diagnostic.getStartPosition(),
diagnostic.getEndPosition(), diagnostic.getSource(), diagnostic.getMessage(null));
}
fileManager.close();
return flag;
}
public static void main(String[] args) throws ClassNotFoundException, IOException {
String targetPath = "src/main/resources/static/";
// 源文件目录
String sourcePath = "src/main/resources/templates/";
File sourceFile = new File(sourcePath);
List<File> sourceFiles = new ArrayList<File>();
compiler(sourceFile, targetPath, sourceFiles);
boolean result = compilerJavaFile(sourceFiles, targetPath);
System.out.println("compiler finish!" + result);
}
想必上述代码中最难看懂的就属这段代码了:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);
Iterable<? extends JavaFileObject> javaFileObjectsFromFiles = fileManager
.getJavaFileObjectsFromFiles(sourceFile);
Iterable<String> options = Arrays.asList("-d", "src/main/resources/static/");
flag = compiler.getTask(null, fileManager, diagnosticCollector, options, null, javaFileObjectsFromFiles).call();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnosticCollector.getDiagnostics()) {
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",
diagnostic.getCode(), diagnostic.getKind(), diagnostic.getPosition(), diagnostic.getStartPosition(),
diagnostic.getEndPosition(), diagnostic.getSource(), diagnostic.getMessage(null));
}
使用StandardJavaFileManager类。这个类能非常好地控制输入、输出,并且能通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现;使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例及通过JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过CompilationTask中的call方法编译源程式。
CompilationTask getTask(Writer out,
JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
Iterable<String> options,
Iterable<String> classes,
Iterable<? extends JavaFileObject> compilationUnits);
在使用这种方法调用Java编译时最复杂的方法就是getTask,下面让我们讨论一下getTask方法。这个方法有如下所示的6个参数:
这些参数大多数都可为null。他们的含义所下。
o ?out::用于输出错误的流,默认是System.err。
o ?fileManager::标准的文件管理。
o ?diagnosticListener: 编译器的默认行为。
o ?options: 编译器的选项
o ?classes:参和编译的class。
最后一个参数compilationUnits不能为null,因为这个对象保存了你想编译的Java文件。
在使用完getTask后,需要通过StandardJavaFileManager的getJavaFileObjectsFromFiles或getJavaFileObjectsFromStrings方法得到compilationUnits对象
调用这两个方法的方式如下:.
Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
Iterable<? extends File> files)
Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(
Iterable<String> names)
String[] filenames = …;
Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromFiles(Arrays.asList(filenames));
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager,
diagnostics, options, null, compilationUnits);
该段代码解释来源于下文链接:
原文链接:https://blog.csdn.net/m_hahahaha1994/article/details/51657969
上述如有问题、意见,请看到的同僚指点提问,你的支持,是我动力所在,谢谢!