Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 04.07.19 14:32
Оценка:
Как-то мне сказали, что maven не хуже Gradle для мультипроектов. Не скажу, что мне так уж нравится Gradle, идеологически мне Maven ближе, но я не понимаю, как правильно делать там даже самые простейшие мультипроекты.

Как я делаю в Gradle:
Делаю родительский проект
Создаю в нём папки для дочерних проектов
Прописываю их в settings.gradle
В дочерних проектах проставляю зависимости друг от друга

Всё, оно просто работает. Я захожу в дочерний проект, пишу gradle build, он при необходимости собирает зависимые дочерние проекты (причём отслеживает изменения на уровне class-файлов, насколько я знаю), собирает текущий проект. Что может быть логичней и проще?

Как я пытаюсь делать в Maven по аналогичной схеме:
Делаю родительский проект:
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>multitest</groupId>
    <artifactId>multitest-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>multitest-test1</module>
        <module>multitest-test2</module>
    </modules>
</project>

Создаю в нём папки multitest-test1 и multitest-test2 и делаю там дочерние проекты:
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>multitest</groupId>
        <artifactId>multitest-parent</artifactId>
        <version>1.0-SNAPSHOT</version>        
    </parent>
    <artifactId>multitest-test1</artifactId>
</project>

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>multitest</groupId>
        <artifactId>multitest-parent</artifactId>
        <version>1.0-SNAPSHOT</version>        
    </parent>
    <artifactId>multitest-test2</artifactId>
    
    <dependencies>
        <dependency>
            <groupId>multitest</groupId>
            <artifactId>multitest-test1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>


Создаю классы где положено:
package multitest.test1;

public class Test1 {
    public static String CONSTANT = "constant-a";
    
    public static String method() {
        return "method-a";
    }
}

package multitest.test2;

import multitest.test1.Test1;

public class Test2 {
    public static void main(String[] args) {
        System.out.println(Test1.CONSTANT);
        System.out.println(Test1.method());
    }
}


Теперь я хочу хотя бы собрать test2 и чтобы оно сообразило, что надо собрать и test1, пошло и собрало.
C:\Users\Vladimir\Projects\test\multitest\multitest-test2>mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< multitest:multitest-test2 >----------------------
[INFO] Building multitest-test2 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The POM for multitest:multitest-test1:jar:1.0-SNAPSHOT is missing, no dependency information available
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.319 s
[INFO] Finished at: 2019-07-04T20:23:33+06:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project multitest-test2: Could not resolve dependencies for project multitest:multitest-test2:jar:1.0-SNAPSHOT: Could not find artifact multitest:multitest-test1:jar:1.0-SNAPSHOT -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException

В общем не получилось у него чего-то там найти. Если я запущу mvn build из родительской папки, то всё вроде как сбилдится, но я же хочу сбилдить конкретный дочерний проект (и все, от которых он зависит), а не все. Как запустить дочерний проект через mvn exec:java -Dexec.mainClass=multitest.test2.Test2 я вообще не понимаю.

Раньше я использовал Maven и такие ситуации решал следующим образом:

Заходим в родительский проект и выполняем mvn install

Теперь все jar-ки скопированы в кеш и вроде как с ними можно работать, т.е. зайти multitest-test2 и что-нибудь сбилдить или запустить.

Но у этого способа есть много минусов. Во-первых и в самых главных, он не отслеживает изменения в зависимых проектах, он просто использует те версии, которые в последний раз копировались в кеш. Т.е. если я сделаю mvn install, потом поменяю исходник в multitest-test1, потом перейду в multitest-test2 и буду его собирать, запускать и тд, то будет использоваться старая версия исходника. Нужно не забывать после каждой правки зависимости делать mvn install. Это очень неудобно.

Во-вторых в общем случае копируются все jar-ки, а не только "библиотеки", что, очевидно, избыточно. У меня, например, три проекта это зависимости и около десятка проектов это запускаемые или веб приложения, которые друг от друга, конечно же, не зависят.

В-третьих мне вообще не нравится идея копировать мои jar-ки в кеш, где по-хорошему должны лежать только скачанные библиотеки. Как-то это странно выглядит.

В общем вопрос — можно ли сделать то, что я хочу, в Maven?
Re: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 04.07.19 16:30
Оценка:
В общем поковырявшись примерно такой вывод.

Нормально оно как не работало, так и не работает. Нормально это как в Gradle. Но есть обходные пути.

Во-первых можно собрать все зависящие от этого пакеты и этот пакет с помощью mvn -am -pl multitest-test2 package (из родительской папки). При этом war, например, соберётся нормально. Правда как запустить — по прежнему не понятно. Возможно через assembly plugin можно собрать jar с зависимостями, пока не пробовал.

Во-вторых если импортировать такой проект в Idea, то там всё работает как надо, т.е. создаются модули (идеевские) и проставляются какие положено зависимости между ними. В принципе запускать из консоли это, наверное, не такой уж и важный юз-кейс, из консоли важно собирать всякие war-ки и дистрибутивы со всеми зависимостями. Со вторым пока не разобрался, но, думаю, с assembly plugin всё должно получиться.
Re: Как правильно готовить maven с мультипроектами?
От: GarryIV  
Дата: 05.07.19 22:40
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Всё, оно просто работает. Я захожу в дочерний проект, пишу gradle build, он при необходимости собирает зависимые дочерние проекты (причём отслеживает изменения на уровне class-файлов, насколько я знаю), собирает текущий проект. Что может быть логичней и проще?

Грейдл удобнее и гибче.

vsb>В общем вопрос — можно ли сделать то, что я хочу, в Maven?

Давно с мавеном не работал но вроде собирать модуль с зависимостями надо как-то так:
mvn package --projects :multitest-test2 --also-make-dependents

запускать с корня.
работает ли --also-make-dependents если собирать не из корня я не помню.

Суть твоих проблем с exec:java я не понял, в чем проблема то? Систем проперти и класспаз можно подкрутить при желании.

Зато мавен быстрый
WBR, Igor Evgrafov
Re[2]: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 06.07.19 17:44
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Суть твоих проблем с exec:java я не понял, в чем проблема то?


Гм, ну основная проблема в том, что он не работает Если запускать из папки с подпроектом, то он не находит test1, от которого зависит. Если запускать из родительской папки, то вообще нифига не получится. Как ты написал, тоже не сработает (только package так работает). Единственный вариант, когда он сработает, это сделать предварительно install из родительской папки, тогда он в кеше найдёт test1.

exec:java фиг с ним, запустить я и из идеи могу. Но есть же куча других плагинов, которые я могу захотеть запустить именно для этого проекта и которым нужны зависимости.

Систем проперти и класспаз можно подкрутить при желании.

GIV>Зато мавен быстрый


Угу. Ещё у него кеш нормальный. У меня специфика — работать надо в оффлайн-окружении. Причём компьютер с IDE и проектами к интернету подключить вообще нельзя, можно только пойти на специальный компьютер с флешкой, что-нибудь сделать и вернуться. Я щас написал специальный прокси (аналог artifactory), запускаю gradle build с ним, а также некоторые дополнительные хаки, чтобы выкачивать sources, в общем собираю так кеш, потом возвращаюсь на основной комп и там уже эти пакеты видны. Работает, но с мавеном это было бы куда проще, собрал на компьютере с интернетом, скопировал папку с кешем и всё.
Re[3]: Как правильно готовить maven с мультипроектами?
От: GarryIV  
Дата: 06.07.19 19:24
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Гм, ну основная проблема в том, что он не работает Если запускать из папки с подпроектом, то он не находит test1, от которого зависит. Если запускать из родительской папки, то вообще нифига не получится. Как ты написал, тоже не сработает (только package так работает). Единственный вариант, когда он сработает, это сделать предварительно install из родительской папки, тогда он в кеше найдёт test1.


vsb>exec:java фиг с ним, запустить я и из идеи могу. Но есть же куча других плагинов, которые я могу захотеть запустить именно для этого проекта и которым нужны зависимости.


Ну это by design так. Это же не кеш, как ты его называешь, а локальное репо, все на него завязано.
WBR, Igor Evgrafov
Отредактировано 06.07.2019 20:28 GarryIV . Предыдущая версия .
Re[4]: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 06.07.19 20:34
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Ну это by design так. Это же не кеш, как ты его называешь, а локальное репо, все на него завязано.


Ну это понятно. Суть в том, что если я делаю изменение в test1 и потом запускаю test2, то оно запускается с тем test1, который был install-ирован в этот локальный репозиторий, а не с теми изменениями, которые я сделал. Т.е. инструмент не обеспечивает отслеживание изменений между проектами, архитектурно не обеспечивает, если так можно выразиться.

Я к чему это всё завёл. Я несколько месяцев назад где-то тут писал (сходу не нашёл), что перешёл на Gradle по сути только из-за того, что Maven адекватно не поддерживает сборки с несколькими проектами. Т.е. я помню, что были проблемы с этим, когда я пробовал. На что мне кто-то возразил, что у Maven нет с этим никаких проблем и видимо я что-то не так делаю. Сейчас руки дошли, я перепроверил, походу я всё же всё так делаю.
Re: Как правильно готовить maven с мультипроектами?
От: Antei США  
Дата: 10.07.19 01:40
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Создаю в нём папки multitest-test1 и multitest-test2 и делаю там дочерние проекты:

vsb>
<project xmlns="http://maven.apache.org/POM/4.0.0"
vsb>         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
vsb>         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
vsb>    <modelVersion>4.0.0</modelVersion>
vsb>    <parent>
vsb>        <groupId>multitest</groupId>
vsb>        <artifactId>multitest-parent</artifactId>
vsb>        <version>1.0-SNAPSHOT</version>        
vsb>    </parent>
vsb>    <artifactId>multitest-test1</artifactId>
vsb></project>



когда референсишь parent из дочернего проекта, укажи relativePath, тогда билд из папки дочернего проекта должен сработать

Notice the relativePath element. It is not required, but may be used as a signifier to Maven to first search the path given for this project's parent, before searching the local and then remote repositories.

<parent>
   <groupId>multitest</groupId>
   <artifactId>multitest-parent</artifactId>
   <version>1.0-SNAPSHOT</version>        
   <relativePath>../pom.xml</relativePath>
</parent>
Re: Как правильно готовить maven с мультипроектами?
От: bzig  
Дата: 10.07.19 18:22
Оценка: 16 (2)
vsb>Как я пытаюсь делать в Maven по аналогичной схеме:

Мавен делали для управления зависимостями и сборкой. Ты по факту используешь (пытаешься) его как скриптовый язык и Мавен тут сливает Грэдлу, который делали как раз как скриптовый язык.

Когда ты на родительском уровне вызываешь какой-то таск, Мавен по дефолту применяет его ко всем и отсюда у тебя ошибка с exec:java, потому что он пытается его вызвать во всех модулях.

В идеологии Мавена, ты должен был бы вызвать package, Мавен создаст все бинарники и потом ты их уже запускаешь без участия Мавена (java -jar multitest-test2.jar)

То, что ты хочешь, тоже можно сделать, но требуется больше конфигурации, которая, помноженная на XML формат, заставляет людей использовать Грэдл.

Вот какие изменения сделал я

  parent pom
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>multitest</groupId>
    <artifactId>multitest-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>multitest-test1</module>
        <module>multitest-test2</module>
    </modules>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                    <mainClass>none</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


  test1 pom
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>multitest</groupId>
        <artifactId>multitest-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>multitest-test1</artifactId>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


  test2 pom
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>multitest</groupId>
        <artifactId>multitest-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>multitest-test2</artifactId>

    <dependencies>
        <dependency>
            <groupId>multitest</groupId>
            <artifactId>multitest-test1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>run-Test2</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <configuration>
                            <skip>false</skip>
                            <mainClass>multitest.test2.Test2</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <!--
        <profile>
            <id>run-AnotherMainClass</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <configuration>
                            <skip>false</skip>
                            <mainClass>multitest.test2.AnotherMainClass</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        -->
    </profiles>

</project>


Теперь из корня можно

mvn -P run-Test2 package exec:java


и оно подхватит изменения и перекомпилирует из других модулей

vsb>Как я делаю в Gradle:

vsb>Делаю родительский проект
vsb>Создаю в нём папки для дочерних проектов
vsb>Прописываю их в settings.gradle
vsb>В дочерних проектах проставляю зависимости друг от друга

У этого есть и обратная сторона — он меееедленноооо зайдёт во все модули, даже если ты знаешь, что это не требуется.

Я уж молчу про самый главный недостаток Грэдла — легкость скриптования отучает людей изучать даже стандартные возможности Грэдла и люди со старта кастомизируют всё по своему и в итоге получаются проекты из 90х, когда каждый проект настроен уникально

Gradle = Ant — XML + maven repos
Re[2]: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 10.07.19 19:56
Оценка:
Здравствуйте, Antei, Вы писали:

A>когда референсишь parent из дочернего проекта, укажи relativePath, тогда билд из папки дочернего проекта должен сработать


Не сработало.
Re[2]: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 10.07.19 20:02
Оценка:
Здравствуйте, bzig, Вы писали:

B>Мавен делали для управления зависимостями и сборкой. Ты по факту используешь (пытаешься) его как скриптовый язык и Мавен тут сливает Грэдлу, который делали как раз как скриптовый язык.


exec:jar это просто пример. dependency:tree тоже скажешь скриптовый? Он тоже не работает. Так можно сказать, что кроме package мавен ни для чего не предназначен. Только он тогда не очень полезен.

B>В идеологии Мавена, ты должен был бы вызвать package, Мавен создаст все бинарники и потом ты их уже запускаешь без участия Мавена (java -jar multitest-test2.jar)


B>То, что ты хочешь, тоже можно сделать, но требуется больше конфигурации, которая, помноженная на XML формат, заставляет людей использовать Грэдл.


B>Вот какие изменения сделал я


Спасибо за пример.

vsb>>Как я делаю в Gradle:

vsb>>Делаю родительский проект
vsb>>Создаю в нём папки для дочерних проектов
vsb>>Прописываю их в settings.gradle
vsb>>В дочерних проектах проставляю зависимости друг от друга

B>У этого есть и обратная сторона — он меееедленноооо зайдёт во все модули, даже если ты знаешь, что это не требуется.


Скорость это не сильная сторона грэдла, это да. Хотя на моих проектах не скажу, что напрягает (без андроида).

B>Я уж молчу про самый главный недостаток Грэдла — легкость скриптования отучает людей изучать даже стандартные возможности Грэдла и люди со старта кастомизируют всё по своему и в итоге получаются проекты из 90х, когда каждый проект настроен уникально


B>Gradle = Ant — XML + maven repos


Ну это уже проблемы людей. Я из кастомизаций только wsimport и xjc вызываю как ant task, потому что встроенных плагинов нет, но там вроде ничего особого. Хотя у меня потребности небольшие и в целом всегда стараюсь подгибать свои требования а не инструмент, обычно результат лучше выходит.
Re[3]: Как правильно готовить maven с мультипроектами?
От: bzig  
Дата: 10.07.19 20:18
Оценка: +1
vsb>exec:jar это просто пример. dependency:tree тоже скажешь скриптовый?

У Мавена проект во главе угла, да. Опять же, если инсталл сделан, то dependency:tree уже и в модуле работает.

Просто не понятен упрёк — ты меняешь зависимости в Тест1, потом идёшь в Тест2 и хочешь посмотреть только его зависимости, но с учётом новых изменений в Тест1? И это настолько частый сценарий, что прямо сразу воспоминается?

Честно говоря, у Грэдла показ зависимостей мне ещё меньше нравится. Вываливает с какой-то зашкаливающей гранулярностью (compile, compileOnly и т.д.), а параметры для уменьшения этого вываливания я никак запомнить не могу.

В Мавене я запускал dependency:tree и получал результат. В Грэдл — запустить, чертыхнуться от говна, поданного на лопате, гугельнуть параметры, запустить ещё раз.

vsb>Он тоже не работает. Так можно сказать, что кроме package мавен ни для чего не предназначен. Только он тогда не очень полезен.


Унификация. Именно Мавену и его репозиториям Ява обязана своим взрывным ростом. Шарить и использовать библиотеки стало мегапросто. Грэдл уже просто паразитирует на Мавене.
Re[5]: Как правильно готовить maven с мультипроектами?
От: Baudolino  
Дата: 12.07.19 09:10
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, GarryIV, Вы писали:


GIV>>Ну это by design так. Это же не кеш, как ты его называешь, а локальное репо, все на него завязано.


vsb>Ну это понятно. Суть в том, что если я делаю изменение в test1 и потом запускаю test2, то оно запускается с тем test1, который был install-ирован в этот локальный репозиторий, а не с теми изменениями, которые я сделал. Т.е. инструмент не обеспечивает отслеживание изменений между проектами, архитектурно не обеспечивает, если так можно выразиться.


А почему он по умолчанию должен пересобирать, а не использовать готовый артефакт? Возможны разные сценарии работы и имхо выбранный в мавене обеспечивает наибольшую совместимость. Соответственно, если есть желание пересобрать несколько артефактов, достаточно сказать об этом мавену явно, уточнив, какие модули будут собраны в mvn install.
Re[6]: Как правильно готовить maven с мультипроектами?
От: vsb Казахстан  
Дата: 12.07.19 09:34
Оценка:
Здравствуйте, Baudolino, Вы писали:

B>А почему он по умолчанию должен пересобирать, а не использовать готовый артефакт?


Потому, что я разрабатываю множество модулей одновременно и готовый артефакт всегда будет устаревшим, если исходники новей, а билд будет вести себя очень странно ("обожаю" дебажиться, когда в IDE исходники одни, а выполняющийся код другой).

B>Соответственно, если есть желание пересобрать несколько артефактов, достаточно сказать об этом мавену явно, уточнив, какие модули будут собраны в mvn install.


Т.е. вручную отслеживать зависимости? Ну это, мягко говоря, неудобно. Не, для этого есть флаги, которые сами пересоберут только то, что нужно, выше по топику уже приводили.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.