Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure a multi-modules Maven project to compile it at once?

Tags:

maven

maven-3

I have a Maven project with multiple modules and sub-modules and i want to compile it at once, i.e. using only one call to "mvn clean install".

For a basic project, the following structure would work:

. ├── modules │   ├── moduleA │   │   └── pom.xml <--- Module A POM │   ├── moduleB │   │   └── pom.xml <--- Module B POM │   └── pom.xml     <--- Super POM (at the root of "modules" folder) └── pom.xml         <--- Aggregator POM 

With the aggregator being:

<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>org.test</groupId>     <artifactId>aggregator</artifactId>     <packaging>pom</packaging>     <version>1.0.0-SNAPSHOT</version>      <modules>         <module>modules</module>         <module>modules/moduleA</module>         <module>modules/moduleB</module>     </modules>  </project> 

The Super 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>org.test</groupId>     <artifactId>super-pom</artifactId>     <packaging>pom</packaging>     <version>1.0.0-SNAPSHOT</version>      <dependencyManagement>         <dependencies>             <dependency>                 <groupId>junit</groupId>                 <artifactId>junit</artifactId>                 <version>4.11</version>                 <scope>test</scope>             </dependency>         </dependencies>     </dependencyManagement>  </project> 

Module A's 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>      <artifactId>moduleA</artifactId>      <parent>         <groupId>org.test</groupId>         <artifactId>super-pom</artifactId>         <version>1.0.0-SNAPSHOT</version>     </parent>  </project> 

Module B is similar.

When at the root of the project, running "mvn clean install" command gives (after cleaning up the .m2/repository folder):

[...] [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO]  [INFO] super-pom .......................................... SUCCESS [  0.450 s] [INFO] moduleA ............................................ SUCCESS [  1.746 s] [INFO] moduleB ............................................ SUCCESS [  0.029 s] [INFO] agregator .......................................... SUCCESS [  0.006 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS 

Now if I want something that is more complex (but still using one super POM), such as:

. ├── modules │   ├── lib1 │   │   ├── moduleA1 │   │   │   └── pom.xml │   │   ├── moduleB1 │   │   │   └── pom.xml │   │   └── pom.xml      <--- lib1 aggregator POM │   ├── lib2 │   │   ├── moduleA2 │   │   │   └── pom.xml │   │   ├── moduleB2 │   │   │   └── pom.xml │   │   └── pom.xml      <--- lib2 aggregator POM │   └── pom.xml          <--- Super POM └── pom.xml              <--- Aggregator POM 

With the root POM being:

<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>org.test</groupId>     <artifactId>agregator</artifactId>     <packaging>pom</packaging>     <version>1.0.0-SNAPSHOT</version>      <modules>         <module>modules</module>         <module>modules/lib1</module>         <module>modules/lib2</module>     </modules>  </project> 

Lib1 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>org.test</groupId>     <artifactId>lib1-agregator</artifactId>     <packaging>pom</packaging>     <version>1.0.0-SNAPSHOT</version>      <modules>         <module>moduleA1</module>         <module>moduleB1</module>     </modules>  </project> 

And, for instance moduleA1 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>      <artifactId>moduleA1</artifactId>      <parent>         <groupId>org.test</groupId>         <artifactId>super-pom</artifactId>         <version>1.0.0-SNAPSHOT</version>     </parent>  </project> 

Maven does not manage to resolve the POM files (after cleaning up the .m2/repository folder):

[INFO] Scanning for projects... [ERROR] [ERROR] Some problems were encountered while processing the POMs: [WARNING] 'parent.relativePath' of POM org.test:moduleA1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleA1/pom.xml) points at org.test:lib1-agregator instead of org.test:super-pom, please verify your project structure @ line 7, column 13 [FATAL] Non-resolvable parent POM for org.test:moduleA1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 [WARNING] 'parent.relativePath' of POM org.test:moduleB1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleB1/pom.xml) points at org.test:lib1-agregator instead of org.test:super-pom, please verify your project structure @ line 7, column 13 [FATAL] Non-resolvable parent POM for org.test:moduleB1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 [WARNING] 'parent.relativePath' of POM org.test:moduleA2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleA2/pom.xml) points at org.test:lib2-agregator instead of org.test:super-pom, please verify your project structure @ line 7, column 13 [FATAL] Non-resolvable parent POM for org.test:moduleA2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 [WARNING] 'parent.relativePath' of POM org.test:moduleB2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleB2/pom.xml) points at org.test:lib2-agregator instead of org.test:super-pom, please verify your project structure @ line 7, column 13 [FATAL] Non-resolvable parent POM for org.test:moduleB2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13  @  [ERROR] The build could not read 4 projects -> [Help 1] [ERROR]    [ERROR]   The project org.test:moduleA1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleA1/pom.xml) has 1 error [ERROR]     Non-resolvable parent POM for org.test:moduleA1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 -> [Help 2] [ERROR]    [ERROR]   The project org.test:moduleB1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleB1/pom.xml) has 1 error [ERROR]     Non-resolvable parent POM for org.test:moduleB1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 -> [Help 2] [ERROR]    [ERROR]   The project org.test:moduleA2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleA2/pom.xml) has 1 error [ERROR]     Non-resolvable parent POM for org.test:moduleA2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 -> [Help 2] [ERROR]    [ERROR]   The project org.test:moduleB2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleB2/pom.xml) has 1 error [ERROR]     Non-resolvable parent POM for org.test:moduleB2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM @ line 7, column 13 -> [Help 2] [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/ProjectBuildingException [ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/UnresolvableModelException 

I need to first build the super pom:

cd modules/ mvn clean install 

And only then will it compile:

[INFO] Reactor Summary: [INFO]  [INFO] super-pom .......................................... SUCCESS [  0.271 s] [INFO] moduleA1 ........................................... SUCCESS [  1.202 s] [INFO] moduleB1 ........................................... SUCCESS [  0.027 s] [INFO] lib1-agregator ..................................... SUCCESS [  0.006 s] [INFO] moduleA2 ........................................... SUCCESS [  0.027 s] [INFO] moduleB2 ........................................... SUCCESS [  0.022 s] [INFO] lib2-agregator ..................................... SUCCESS [  0.007 s] [INFO] agregator .......................................... SUCCESS [  0.007 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS 

How would you structure the project to make it work without this two-steps compilation?

[EDIT]: as discussed in the comments, adding the relativePath of the Super POM to the modules POMs would make the code compile with one command line.

However, if I want to distribute only lib1 to some developers, even though my super POM is on a Maven repository, lib1 would not compile without the whole project structure. This makes the project less modular.

like image 237
Ben Avatar asked Jan 27 '16 10:01

Ben


People also ask

How do you create a multi-module project?

A multi-module project is built from an aggregator POM that manages a group of submodules. In most cases, the aggregator is located in the project's root directory and must have packaging of type pom. The submodules are regular Maven projects, and they can be built separately or through the aggregator POM.

Does Maven support multi project build?

As seen in the introduction to the POM, Maven supports project aggregation in addition to project inheritance. This section outlines how Maven processes projects with multiple modules, and how you can work with them more effectively.

Can a Maven project have multiple pom files?

Yes you can use Maven Profiles to manage this. Obviously you can tweak this approach to suit your needs however works best.


1 Answers

Let me start like you did, but I name the things a little bit differently:

. ├── modules-root │   ├── moduleA │   │   └── pom.xml <--- Module A POM │   ├── moduleB │   │   └── pom.xml <--- Module B POM │   └── pom.xml     <--- modules root └── pom.xml         <--- project-root 

Let's start with the project-root, which will look like this:

<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>org.test</groupId>     <artifactId>project-root</artifactId>     <packaging>pom</packaging>     <version>1.0.0-SNAPSHOT</version>      <dependencyManagement>         <dependencies>             <dependency>                 <groupId>junit</groupId>                 <artifactId>junit</artifactId>                 <version>4.11</version>                 <scope>test</scope>             </dependency>         </dependencies>     </dependencyManagement>      <modules>        <module>modules-root</module>     </modules>  </project> 

The module-parent will look like this. I will emphasis that this contains only the reference to the moduleA and moduleB and will inherit from the project-root:

<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>org.test</groupId>         <artifactId>project-root</artifactId>         <version>1.0.0-SNAPSHOT</version>     </parent>      <groupId>org.test.module</groupId>     <artifactId>module-parent</artifactId>     <packaging>pom</packaging>      <modules>         <module>moduleA</module>         <module>moduleB</module>     </modules> </project> 

moduleA will look like this. Pay attention that this will inherit from module-parent (parent) which is exactly one level above...

<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>org.test.module</groupId>         <artifactId>module-parent</artifactId>         <version>1.0.0-SNAPSHOT</version>     </parent>      <artifactId>moduleA</artifactId>     <packaging>..</packaging>      <....other dependencies..> </project> 

If you use this kind of structure you can simply go to the project-root level and do:

mvn clean install 

Furthermore afterwards you can use things like this:

mvn -pl moduleA ... 

...to build only moduleA (but stay at the project-root level...).

module-parent might look like wasted or superfluous in this example, but if you get more modules you could define their supplemental dependencies via dependencyManagement or may changing plugin configurations via pluginManagement which will only be used in this sub area (moduleA, moduleB, ...). If your project becomes larger, you will get more module-parents in parallel..which contain different parts of your applications...and different intentions which can be achieved with this structure.

One more thing is to mention; I have changed the groupId from org.test to org.test.module in the module-parent. This is sometimes useful if you have a large number of modules cause the groupId represents the folder structure in your repository (as java packages do in a Java project)... this give you an better overview...

The project-root is the location to define the overall usable dependencies via dependencyManagement etc....and the used plugins which should be defined via pluginManagement... or may be using maven-enforcer-plugin to define overall project rules...

Typical scenarios for this kind of structure are Java EE projects or other large projects (may be with 300...or 1000 modules yes they exist)...

If you get more modules you can use the multi-thread capability of maven and build your project with:

mvn -T 4 clean install  

from the project-root which reduces the build time dramatically.

like image 99
khmarbaise Avatar answered Oct 09 '22 04:10

khmarbaise