JSR 199引入了Java編譯器API。如果使用JDK 6 的話,可以通過此API來動態編譯Java代碼。比如下面的代碼用來動態編譯最簡單的Hello World類。該Java類的代碼是保存在一個字符串中的。
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* 在程序內部調用編譯器,動態編譯運行
*
*/
public class CompilerTest {
public static void main(String[] args) throws Exception {
String source = "public class Main { public static void main(String[]"
+" args) {System.out.println(\"Hello World!\");} }";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
StringSourceJavaObject sourceObject = new CompilerTest.StringSourceJavaObject("Main", source);
String flag = "-d";
String outDir = System.getProperty("user.dir")+"/bin";
//設置Main的class目錄也在eclipse默認編譯的bin目錄下,不設置則Main在abcc下
//Iterable<String> stringDir = Arrays.asList(flag,outDir);
Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
CompilationTask task = compiler.getTask(null, fileManager, null,null, null, fileObjects);
//CompilationTask task = compiler.getTask(null, fileManager, null,stringDir, null, fileObjects);
boolean result = task.call();
if (result) {
System.out.println("編譯成功。");
//運行
Class<?> clazz = Class.forName("Main");
Method method = clazz.getMethod("main", new Class<?>[]{String[].class});
method.invoke(null, new Object[]{null});
}
}
static class StringSourceJavaObject extends SimpleJavaFileObject {
private String content = null;
public StringSourceJavaObject(String name, String content)throws URISyntaxException {
super(URI.create("string:///" + name.replace('.', '/')
+ Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return content;
}
}
}
運行此類但拋出ClassNotFoundException ,Main找不到。在eclipse 導航中發現Main類(代碼中的動態編譯類)class文件生成在工程主目錄下,而在eclipse中建的類(CompilerTest)的編譯class的位置在bin下,用ComplierTest加載器在其目錄bin下加載顯然就找不到了。
解決辦法: Java編譯器API實際上是調用系統環境中的javac命令,在終端下輸入javac命令,會發現javac帶有n多的參數,其中有一個是-d 可以指定編譯後的class文件存放目錄。但在java編譯器的API是如何實現的呢? 可以在JavaCompiler的getTask方法進行設置:
CompilationTask getTask(Writer out, JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options,Iterable<String> classes,Iterable<? extends JavaFileObject> compilationUnits);
其中的options就是指定了javac的參數。 在此將上面代碼的註釋去掉即可。 關於其他的動態編譯的用法如動態加載單獨文件裏的類等,可參考其他API。
看參考http://www.iteye.com/topic/608485