Укажите выходной путь для динамической компиляции

Моя динамическая компиляция на 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, но сообщение об ошибке - «Недопустимый флаг».


person Dan Rosenstark    schedule 08.01.2010    source источник
comment
+1 за то, что предупредил меня, что сейчас существует такая вещь, как динамическая компиляция!   -  person Carl Smotricz    schedule 08.01.2010
comment
Всегда было, теперь это встроено!   -  person Dan Rosenstark    schedule 08.01.2010


Ответы (3)


Код в первом сообщении будет работать, но выдается следующая ошибка:

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

Это потому, что передача "-d folder" заставляет синтаксический анализатор думать, что он анализирует одну опцию. Параметры должны быть разделены, как "-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();
person Gima    schedule 23.09.2011
comment
как насчет таких путей, как c: \\ foo bar \\ foo или c: / foo bar / foo? Можно ли правильно разбирать пробелы или косые черты? - person Gobliins; 05.11.2015
comment
Я не знаю, но я предполагаю, что экранирование не требуется, поскольку аргументы теперь передаются правильно (и поскольку природа исходной проблемы была точно такой же, как у параметров, которые не анализируются отдельно). Попытаться сообщить об этом? - person Gima; 07.11.2015

Сегодня я столкнулся с той же проблемой.

Ответ (используя обычный метод 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();
person OscarRyz    schedule 08.09.2010
comment
Я давно не рассматривал эту проблему. Значит, вы говорите, что ваш ответ действительно решает всю проблему? - person Dan Rosenstark; 08.09.2010
comment
Работает хорошо - так же, как использование -d в параметре параметров getTask (), но чище. - person Atorian; 26.08.2014

У меня нет опыта работы с инструментами динамического компилятора Java 6. Но больше никто не ответил :)

Задача компиляции получает объект FileManager. Если вы используете стандартный, то классы создаются в дереве исходных каталогов. Что вы можете сделать, так это предоставить свой собственный подкласс FileManager с переопределенным методом getFileForOutput. Описание API getFileForOutput указывает, что это повлияет на то, куда будут отправляться ваши выходные файлы (= класс).

Обновить

Как подключить файловые менеджеры

Подклассы 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 отдельно для каждого исходного файла.

person Carl Smotricz    schedule 08.01.2010
comment
Это может быть правдой, но, к сожалению, getJavaFileObjects есть только в StandardJavaFileManager .... Я посмотрю, что можно сделать в любом случае. Если бы это был Ruby, вашего ответа было бы достаточно, чтобы обезьяна запатчила и готово :) - person Dan Rosenstark; 08.01.2010
comment
В Java путь состоит в подклассе ... ForwardingJavaFileManager реализует StandardJavaFileManager, и это тот, который вы бы использовали. - person Carl Smotricz; 08.01.2010
comment
Фактически, у него есть конструктор, который можно обернуть вокруг FileManager, полученного от compiler. Конечно, вы захотите сделать этот конструктор общедоступным в производном классе. - person Carl Smotricz; 08.01.2010
comment
Спасибо, Карл, только что попробовал (заключил fileManager в подпрограмму ForwardingJavaFileManager ‹StandardJavaFileManager›, а затем передал это задаче). Проблема в том, что getFileForOutput НИКОГДА не вызывается. Но ForwardingJavaFileManager НЕ реализует StandardFileManager. - person Dan Rosenstark; 08.01.2010
comment
Боюсь, ты прав. Извините за погоню за дикими гусями! - person Carl Smotricz; 08.01.2010
comment
Добавлена ​​некоторая информация о том, как творить чудеса объединения файловых менеджеров. Это прямо из Compiler API, так что, надеюсь, поможет. - person Carl Smotricz; 08.01.2010
comment
Спасибо за вашу настойчивость. Я использовал getFileObjects, а не getJavaFileObjects, поэтому создание подклассов действительно работает, но я все еще не могу достичь окончательного результата, потому что я не знаю, как создать объект Location (заменяющий тот, который передан getJavaFileObjects), который вызывает вывод классов на новое место. - person Dan Rosenstark; 09.01.2010
comment
Создал собственное демонстрационное приложение. Он работает и помещает сгенерированные классы туда, куда я его прошу. Пожалуйста, взгляните на мой обновленный ответ! - person Carl Smotricz; 09.01.2010
comment
Это потрясающе. Пакет яр. Я польщен. Пока это будет работать, я буду кричать в ответ, когда буду интегрировать его, чтобы еще раз поблагодарить вас. Похоже, что args может быть массивом String, так что это должно сработать. - person Dan Rosenstark; 09.01.2010
comment
Хех, у меня есть проект Eclipse под названием StackOverflowJava, и в его папке src я создаю классы, названные в честь плакатов, когда код помещается в один класс; или пакеты, названные в честь плакатов, когда я предполагаю, что потребуется несколько классов. Он становится огромным хранилищем всяческих сумасшедших маленьких проектов! - person Carl Smotricz; 09.01.2010
comment
Я должен знать, но не знаю, как массивы String работают в контексте списков переменных аргументов. Но я думаю, у тебя все получится. Если нет, то всегда ТАК. Рад, что смог помочь! - person Carl Smotricz; 09.01.2010
comment
Вот ваш класс, немного переработанный: compileyouidontevenknowyou .blogspot.com / 2010/01 /. Добавьте его в рекурсивный список файлов (я скоро опубликую свой в своем блоге), и все готово. - person Dan Rosenstark; 09.01.2010