LoginSignup
19
18

More than 5 years have passed since last update.

Javaで動的コンパイル

Posted at

はじめに

JavaでBeanのソースをStringとして自動生成して、それをコンパイルできないかなー、とやってみたテストコードです。ソースコンパイル後、リフレクションでメソッドを実行します。
ソースは、
https://github.com/xaatw0/quiita/tree/master/src/dynamiccompile
にあります。
参考は、
http://waman.hatenablog.com/entry/20110310/1299721161

まずは、コンパイル用のクラスを作成

CompileTest.java
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;
    }

}

このクラスのインスタンスを生成するクラスごとに作るようだ。

ソース作って、コンパイルして、メソッド呼び出して。

CompileTest.java

@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));
}

19
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
18