#java #maven
#java #maven
Вопрос:
tl; dr-edition: у меня есть компиляция, я знаю, что она завершится неудачей, но мне нужно подмножество классов, которые все еще можно скомпилировать в моей target/classes
папке после компиляции. Я настроил <failOnError>false</failOnError>
, но классы не генерируются, даже фиктивный класс, который не зависит от каких-либо других классов, кроме Object
. Есть ли какая-то конфигурация для достижения этого?
У меня есть проект на базе maven, рабочий процесс которого состоит в основном из следующих (соответствующих) целей:
...
-
init-compile
Генератор кода (ниже) использует конфигурацию, основанную на отражении, поэтому в первом проходе я хочу попытаться скомпилировать как можно больше проекта, чтобы там не было ClassNotFoundExceptions . Эта компиляция настроена
<failOnError>false</failOnError>
так, чтобы сборка продолжалась.К сожалению (вы могли бы назвать это недостатком дизайна), конфигурация используется как для генерации кода (указание файла OWL и пространства имен для сопоставления пакетов), так и во время выполнения, поэтому она также содержит другие элементы, которые не нужны для генератора кода, но все еще читаются и, следовательно, необходимы в пути к классу, чтобыуспешно.
-
generate-model
На этом этапе некоторые классы модели генерируются из OWL-онтологии, создавая код, который делает остальную часть проекта полностью компилируемой.
-
default-compile
Теперь, очевидно, остальные классы должны быть скомпилированы
-
save-model
Теперь экземпляры из онтологии считываются и сериализуются в файл для выполнения
-
...
Примечание: как генерировать, так и сохранять использование модели maven-exec-plugin
, но я искренне не думаю, что это вообще имеет значение.
Вопрос:
Когда я запускаю свою сборку mvn -e -U clean package source:jar javadoc:jar install:install
, она завершается сбоем во время generate-model
цели с ошибками, которых я пытаюсь избежать. target/classes
пусто, поэтому кажется, что компилятор не выдает подмножество классов, которые он мог / должен был обрабатывать. Есть ли способ добиться этого?
У меня есть два обходных пути, которые мне оба не нравятся:
- Редактирование конфигурационного файла «AST» перед его анализом в Java-объекты, чтобы анализировалась только часть, относящаяся к генератору кода (требуется настройка кода, к которому у меня есть доступ, но мой проект должен считаться неизменяемым);
- и настроить
init-compile
цель так, чтобы она включала только необходимые классы (слишком негибко, потому что POM должен / может быть шаблоном для будущих приложений, использующих ту же модель).
Если вы можете представить себе другой способ решения моей проблемы, который вы можете увидеть из моего описания, я тоже был бы рад их услышать!
Комментарии:
1. Может быть, я что-то упускаю — ваша сборка не работает, когда вы перемещаете свою цель создания модели на этап генерации источников?
2. Конфигурация предоставляется в пути к классу, где она также находится во время выполнения приложения, забыл сказать, что, поэтому generate-model (и init-compile перед этим) выполняются во время ресурсов процесса. Но, как указано выше, реальная проблема более или менее заключается в том, что мне нужна начальная, неполная компиляция, которая предоставляет классы, на которые ссылаются в конфигурации. Думаю, я закончу с первым обходным путем, но мне все еще интересно, как этого добиться…
Ответ №1:
Во-первых, позвольте мне кратко изложить вашу проблему, чтобы убедиться, что я правильно ее понял.
-
У вас есть набор классов, функция которых в их скомпилированном виде заключается в настройке как генератора кода, так и среды выполнения. (Подмножество из них относится к генератору кода, но генерация завершится неудачно, если не будет представлена полная конфигурация. Таким образом, мы можем рассматривать это так, как если бы вся конфигурация была необходима.)
-
Затем у вас есть набор классов, которые будут сгенерированы как исходный код. У них есть время генерации, возможно, время компиляции и зависимость времени выполнения от классов конфигурации.
-
Наконец, у вас есть какой-то другой код, который зависит от времени компиляции от сгенерированных классов и зависит от времени выполнения как от сгенерированных классов, так и от классов конфигурации.
-
Однако ваши классы конфигурации не имеют никаких зависимостей во время компиляции ни от сгенерированных классов, ни от другого кода. Вы явно не говорите об этом, но я предполагаю это, иначе у вас проблема с циклической зависимостью.
Вот мое предложение: разделите проект на многомодульный («реакторный») проект. Ваш текущий проект будет модулем проекта reactor. Создайте новый модуль с именем «config» или аналогичный и переместите в него свои классы конфигурации. Пусть основной модуль зависит от него.
Если вам не нравятся многомодульные проекты, вы можете добиться того же, объявив дополнительное выполнение плагина компиляции, привязанного к фазе генерации исходных текстов. (Вы не говорите, но я предполагаю, что вы выполняете генерацию кода на этом этапе. Если вы объявите плагин компиляции перед плагином генератора кода в POM, Maven выполнит их в том же порядке.) Вы бы использовали фильтр «включить» плагина компиляции для компиляции только классов конфигурации. Для этого вам нужно будет иметь классы конфигурации в отдельном пакете от всех остальных, что в любом случае является хорошей практикой.
Комментарии:
1. Привет! Спасибо за ваш ответ! Разделение проекта теоретически является вариантом, но я думаю, что это немного излишне для моего использования (это тестирование производительности: у нас есть отдельные проекты для тестовых случаев, поэтому удвоение количества проектов является громоздким). Просто чтобы вы знали, я выбрал вариант обходного пути 1, где я прочитал всю конфигурацию, но проанализировал только ее поддерево как объекты Java 😉
Ответ №2:
Есть одно очень удобное решение — использовать Eclipse Java Compiler (EJC) вместо стандартного Oracle javac! Одним из преимуществ ECJ перед javac является то, что в нем допустимы ошибки, он пытается скомпилировать как можно больше и сохраняет уже сгенерированные файлы классов. EJC был разработан для использования в IDE, для высокоинтерактивной работы, где частичная компиляция является обязательной, но его также можно использовать как CLI или плагин Maven. Ребята из Plexus предоставляют EJC в качестве удобной зависимости Maven.
В Maven можно подключать компиляторы. У вас может быть несколько компиляций (выполнения компиляции), определенных в одном POM, и вы можете использовать разные компиляторы для каждого, предоставляя разработчику широкий выбор опций.
Пример кода POM:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>pre-compilation</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compilerId>eclipse</compilerId>
<!-- IMPORTANT. Select EJC as compiler instead of javac -->
<failOnError>false</failOnError>
<!-- IMPORTANT. When ECJ is used errors are reported
only as warnings, it continues in compilation,
try to compile as much as possible, keeps already
generated classes in target/classes -->
</configuration>
</execution>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<!-- in the end recompile everything with standard javac.
This time no compilation errors are expected or tolerated. -->
<goals>
<goal>compile</goal>
</goals>
<configuration>
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</plugin>
<!-- generate sources. This plugin executes in facet BETWEEN the compilations due to
'generate-sources' phase binding and relative position in POM -->
<plugin>
<groupId>org.eclipse.xtext</groupId>
<artifactId>xtext-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>generate-the-stuff</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
Благодарности Габриэлю Акселю за его статью http://www.gabiaxel.com/2011/10/replacing-javac-with-eclipse-compiler.html
Этот подход может решить некоторые сложные циклические зависимости «от источника к сгенерированному источнику к источнику«, потенциально неразрешимые путем разделения на отдельные модули.
Кроме того, я хотел интегрировать генерацию исходного кода наиболее прозрачным способом. Необходимость перетасовки кода на основе зависимостей от сгенерированных источников окончательно нарушит его. Я хочу сгруппировать свой код на основе логического дизайна не из-за технических особенностей.
Если у вас генератор кода происходит с xtext, как в моем случае, и вы используете xtext-maven-plugin, скажем, недавно выпущенный 2.5.0, вам не нужно ничего настраивать, как в примере выше, плагин делает именно это под капотом.