用Java进行动态编译
首先
这是一个测试代码,我尝试自动将Bean的源代码生成为字符串,然后尝试编译它。编译后,通过反射执行其中的方法。
源代码位于
https://github.com/xaatw0/quiita/tree/master/src/dynamiccompile
参考资料为
首先,创建一个用于编译的类。
private class DynamicJavaSourceCodeObject extends SimpleJavaFileObject {
private final String code;
public DynamicJavaSourceCodeObject(String name, String code) {
// Windowsで動く形式。Unix系だと異なるのか。
super(URI.create("string:///" + name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code ;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)throws IOException {
return code;
}
}
好像是需要为每个生成该类实例的类单独创建一个。
制作源代码,进行编译,调用方法。
@Test
public void compile(){
// コンパイルしたクラスファイルの出力先のルート
String DEST_DIR = "bin";
// クラスのパッケージ名。テストクラスと同じパッケージ名にした。
String PACKAGE_NAME = getClass().getPackage().getName();
// クラスの名称
String CLASS_NAME = "DynamicCompileTest";
// パッケージ名 + クラス名
String QUALIFIED_CLASS_NAME = PACKAGE_NAME +"."+ CLASS_NAME;
// 作成するクラスのソース。変数valueにsetter,getterメソッドがあるだけ。
String SOURCE =
"package "+ PACKAGE_NAME +";" +
"class "+ CLASS_NAME +" {" +
"private int value; " +
"public int getValue(){ return value;} " +
"public void setValue(int value){this.value = value;} " +
"}";
/********** 動的コンパイル *********/
// (1) コンパイルに渡すソースコードやオプションを作成
// コンパイル後にエラーが無いか調べる(ステップ(4)参照)
DiagnosticCollector<JavaFileObject> diags = new DiagnosticCollector<JavaFileObject>();
// コンパイル・オプション
List<String> options = Arrays.asList("-d", DEST_DIR);
// Java のソースコード
List<? extends JavaFileObject> src = Arrays.asList(
new DynamicJavaSourceCodeObject(QUALIFIED_CLASS_NAME, SOURCE)
);
// (2) コンパイラ・オブジェクト取得
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// (3) コンパイル実行
JavaCompiler.CompilationTask compilerTask = compiler.getTask(null, null, diags, options, null, src);
// (4) コンパイル・エラーのチェック
if (!compilerTask.call()){
for (Diagnostic diag : diags.getDiagnostics()){
System.out.format("Error on line %d in %s", diag.getLineNumber(), diag);
}
}
// bin\dynamiccompile に DynamicCompileTest.class が生成されている
// 既存のクラスがあった場合、更新される
/********** リフレクションでインスタンス生成、メソッド実施 *********/
Object obj = null;
try {
// インスタンスの生成
obj = Class.forName(QUALIFIED_CLASS_NAME).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
try {
// setValue(1)で値を設定
Method setMethod = obj.getClass().getMethod("setValue", int.class);
setMethod.invoke(obj, 1);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
Object result = null;
try {
// getValue()で値を取得
Method getMethod = obj.getClass().getMethod("getValue");
result = getMethod.invoke(obj);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
assertThat(result, is(1));
}