12

Java 6 での私の動的コンパイルは完全に機能しています。ただし、出力パスを変更したいと思います。私はたくさんのことを試しました(私はあなたを惜しみません)無駄にしました。とにかく、ここに作業コードがあります

String[] filesToCompile = { "testFiles/Something.java" };
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(filesToCompile);
CompilationTask task = compiler.getTask(null, fileManager, null,null, null, compilationUnits);
System.out.println("Good? " + task.call());

しかし、出力はソースディレクトリに送られますが、これは私が望むものではありません。

答えは にあるのではないかと思いcompiler.getTaskますが、API はいくつかのパラメーターが何を意味するかについてあまり明確ではありません。または、おそらくfileManagerの何か。私はもう試した

fileManager.setLocation(StandardLocation.locationFor("testFiles2"), null);

繰り返しますが、推測はおそらく良い考えではありません。

ありがとう!

編集:私もこのようにオプションを使ってみました(もっとコンパクトな方法があればごめんなさい):

    final List<String> optionsList = new ArrayList<String>();
    optionsList.add("-d what");
    Iterable<String> options = new Iterable<String>() {         
        public Iterator<String> iterator() {
            return optionsList.iterator();
        }
    };

オプションを getTask に渡しますが、エラー メッセージは「Invalid Flag」です。

4

3 に答える 3

14

私は今日、これと同じ問題に直面していました。

答えは(getTask`runの代わりに通常の方法を使用して)FileManagerで出力ディレクトリを指定することです:

fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputDir));

以上です!!:)

ドキュメントは少し誤解を招く可能性があります。つまり、サンプルが非常に便利になる可能性があります。しかし、結局それは私をそこに連れて行きました。

編集

実行中のサンプルは次のとおりです。

    // write the test class
    File sourceFile   = new File("First.java");
    FileWriter writer = new FileWriter(sourceFile);

    writer.write(
            "package load.test;\n" +
            "public class First{}"
    );
    writer.close();

    // Get the java compiler for this platform
    JavaCompiler compiler    = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(
            null,
            null,
            null);

    //--           H E R E    --// 
    // Specify where to put the genereted .class files
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, 
                            Arrays.asList(new File("/tmp")));
    // Compile the file
    compiler
        .getTask(null,
                fileManager,
                null,
                null,
                null,
                fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile)))
        .call();
    fileManager.close();

    // delete the file
    sourceFile.deleteOnExit();
于 2010-09-08T04:53:28.277 に答える
7

最初の投稿のコードは機能しますが、次のエラーがスローされます。

java.lang.IllegalArgumentException: invalid flag: -d folder

これは、渡す"-d folder"ことで、パーサーが 1 つのオプションを解析していると見なすためです。オプションは のように区切る必要があります"-d", "folder"

作業例は次のとおりです。

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = javaCompiler.getStandardFileManager(null, null, null); 

String[] options = new String[] { "-d", "output" };
File[] javaFiles = new File[] { new File("src/gima/apps/flip/TestClass.java") };

CompilationTask compilationTask = javaCompiler.getTask(null, null, null,
        Arrays.asList(options),
        null,
        sjfm.getJavaFileObjects(javaFiles)
);
compilationTask.call();
于 2011-09-23T16:34:30.727 に答える
4

Java 6 動的コンパイラ ツールの使用経験はありません。しかし、誰も答えていません:)

コンパイル タスクはFileManagerオブジェクトを取得します。標準のものを使用する場合、クラスはソース ディレクトリ ツリーに生成されます。あなたができることは、独自の FileManager サブクラスにオーバーライドされたgetFileForOutputメソッドを提供することです。getFileForOutput の API の説明は、これが出力 (= クラス) ファイルの場所に影響を与えることを示しています。

アップデート

ファイルマネージャーを接続する方法

ForwardingJavaFileManager、ForwardingFileObject、および ForwardingJavaFileObject サブクラス化は、コンストラクターを呼び出すのではなく、コンパイラーでメソッドを呼び出すことによって作成されるため、標準のファイルマネージャーの動作をオーバーライドするために使用できません。代わりに、転送 (または委任) を使用する必要があります。これらのクラスを使用すると、動作をカスタマイズしながら、ほとんどの呼び出しを特定のファイル マネージャーまたはファイル オブジェクトに簡単に転送できます。たとえば、JavaFileManager.flush() へのすべての呼び出しをログに記録する方法を考えてみましょう。

   final Logger logger = ...;
   Iterable<? extends JavaFileObject> compilationUnits = ...;
   JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
   JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) {
       public void flush() {
           logger.entering(StandardJavaFileManager.class.getName(), "flush");
           super.flush();
           logger.exiting(StandardJavaFileManager.class.getName(), "flush");
       }
   };
   compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();

更新 2

私は動的コンパイルを読み、これを行うために独自のアプリを構築しました。このコードには少し過剰な儀式が含まれています (つまり、単純化できます) が、機能します!

package yar;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class DynamicCompiler {

   JavaCompiler compiler;

   public DynamicCompiler() {
      this.compiler = ToolProvider.getSystemJavaCompiler();
      if (this.compiler == null) {
         throw new NullPointerException("Cannot provide system compiler.");
      }
   }

   public void compile() {
      this.compiler.run(null, System.out, System.err, 
            "-d", "testFiles2", 
            "testFiles/Hello1.java", "testFiles/Hello2.java");
   }

   /**
    * @param args
    */
   public static void main(String[] args) {
      try {
         DynamicCompiler dc = new DynamicCompiler();
         dc.compile();
      } catch (Exception e) {
         System.err.println(e.getMessage());
      }
   }

}

このコードを動的に生成された Java ファイルのリストで動作させる方法がわかりません。おそらくcompiler.run、ソースファイルごとに個別に行うだけです。

于 2010-01-08T14:44:06.313 に答える