2011-11-03 8 views
24

私はプログラム的JavaCompilerクラスを使用してJavaクラスをコンパイルする方法を説明する多くの参照を発見した:しかし、私は私がプログラムで生成されたソースコードを(コンパイルせ、オープンソースのライブラリーがあるかどうかを知りたいプログラムでJavaソースコードをメモリ内でコンパイルすることはできますか?

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
int result = compiler.run(null, null, null, "a_file_name"); 

をしたがって、srcファイルが関与することなく)、出力ストリームにバイトコードを生成します(ファイルシステムにクラスファイルを生成することはありません)。

例えば、私はこのような何かを書くことができることを探しています:任意の助け

InputStream input = generateSourceCode(); 
OutputStream output = getByteCode(input); 
doCoolStuffWithByteCode(output); 

感謝を。

+0

デモについては、[SSCCE ** Text Based ** Compiler](http://pscode.org/stbc/)を参照してください。ジェームス&ブライアンが言及しているもののSTBCは 'JavaCompiler' /' SimpleJavaFileObject'を使います。 –

答えて

38

開始するには、JavaCompiler APIを参照してください。基本的に:

  1. Javaクラスを文字列で作成します。
  2. SimpleJavaFileObjectを拡張するクラスに文字列を配置します。
  3. JavaCompilerインスタンスを使用してコンパイルします。

最後に、メソッドを新しいクラスとして呼び出します。ここで


はJDK6 +で動作exampleです:

import java.io.IOException; 
import java.io.PrintWriter; 
import java.io.StringWriter; 
import java.lang.reflect.InvocationTargetException; 
import java.net.URI; 
import java.util.Arrays; 

import javax.tools.Diagnostic; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.SimpleJavaFileObject; 
import javax.tools.ToolProvider; 
import javax.tools.JavaCompiler.CompilationTask; 
import javax.tools.JavaFileObject.Kind; 

public class CompileSourceInMemory { 
    public static void main(String args[]) throws IOException { 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

    StringWriter writer = new StringWriter(); 
    PrintWriter out = new PrintWriter(writer); 
    out.println("public class HelloWorld {"); 
    out.println(" public static void main(String args[]) {"); 
    out.println(" System.out.println(\"This is in another java file\");");  
    out.println(" }"); 
    out.println("}"); 
    out.close(); 
    JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString()); 

    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); 
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); 

    boolean success = task.call(); 
    for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 
     System.out.println(diagnostic.getCode()); 
     System.out.println(diagnostic.getKind()); 
     System.out.println(diagnostic.getPosition()); 
     System.out.println(diagnostic.getStartPosition()); 
     System.out.println(diagnostic.getEndPosition()); 
     System.out.println(diagnostic.getSource()); 
     System.out.println(diagnostic.getMessage(null)); 

    } 
    System.out.println("Success: " + success); 

    if (success) { 
     try { 
     Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class }) 
      .invoke(null, new Object[] { null }); 
     } catch (ClassNotFoundException e) { 
     System.err.println("Class not found: " + e); 
     } catch (NoSuchMethodException e) { 
     System.err.println("No such method: " + e); 
     } catch (IllegalAccessException e) { 
     System.err.println("Illegal access: " + e); 
     } catch (InvocationTargetException e) { 
     System.err.println("Invocation target: " + e); 
     } 
    } 
    } 
} 

class JavaSourceFromString extends SimpleJavaFileObject { 
    final String code; 

    JavaSourceFromString(String name, String code) { 
    super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE); 
    this.code = code; 
    } 

    @Override 
    public CharSequence getCharContent(boolean ignoreEncodingErrors) { 
    return code; 
    } 
} 
+0

+1ポインタに感謝します。最後のリンクは、私が探しているものをほとんど示しています。唯一の違いは、あらかじめコンパイルするクラスの名前を知っている必要があります。唯一のことは、完全なソースコードです。 – Sergio

+0

「public class」という単語を検索するだけで、次の単語がおそらくクラス名になりますか? –

+0

私は手動でソースコードをスキャンすることができますが、もっとエレガントなことができるかどうかは不思議です。ありがとう! – Sergio

0

我々は(質問が古いの一種であるのJavaOne 2016で、このユースケースについての講演を行いましたが、それでもいくつかの興味があるように思われます)。

repositoryがあり、javacのインメモリを使用した実際のコード生成の例があります。

具体的には、1つのクラスに対してスレッドの安全性(サーバーのコンテキストで使用する)を処理するメモリでこれを行う方法の例については、SimpleJavaCompilerを参照してください。マルチクラスのシナリオに容易に適用できます。

クラスの読み込みとコード生成(変数のスコープ、固有の名前の生成、名前のシャドーイングなど)も扱うクラスがあります。

関連する問題