Multi-Module Maven Projects: Difference between revisions
(64 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* Guide to Working with Multiple Modules https://maven.apache.org/guides/mini/guide-multiple-modules.html | * Guide to Working with Multiple Modules https://maven.apache.org/guides/mini/guide-multiple-modules.html | ||
* A multi-module project http://books.sonatype.com/mvnex-book/reference/multimodule.html | |||
=Internal= | =Internal= | ||
* [[Maven Concepts#Subjects|Maven Concepts]] | * [[Maven Concepts#Subjects|Maven Concepts]] | ||
* [[Maven assembly Plugin|The assembly Plugin]] | |||
=Overview= | =Overview= | ||
For guidelines on when it is appropriate to use modules, and when separate projects, see "[ [#When_We_Should_Use_Modules.3F|When We Should Use Modules ?]]" section. | For guidelines on when it is appropriate to use modules, and when separate projects, see "[[#When_We_Should_Use_Modules.3F|When We Should Use Modules ?]]" section. | ||
=The Reactor= | |||
=When We Should Use Modules?= | |||
Two major benefits of a multi-module project are that all the parts can be built with a single command, and Maven handles the correct build order. | |||
=Modules and Versions= | |||
Different modules of the same project can have different versions, or they can all share the [[Maven Concepts#Version|parent's version]]. | |||
==Single Module== | |||
When a project consists of a single (implicit) module, whose POM is the only POM of the project, the version is given by the <version> element of the POM file. | |||
==Lockstep Versions== | |||
This model is appropriate when all modules maintain a common version. This model is simpler, conceptually, than "[[#Independent_Versions|Independent Versions]]", described below. | |||
The common version is specified in the [[#The_Parent_POM|parent POM]], as the main <version> element. The module may declare literally the same version in their <version> elements, but that is not absolutely necessary. If the <version> element is not explicitly specified in the module's POM, it defaults to [[Maven_Standard_System_Properties#project.version|${project.version}]], which read its value from the root POM <version> element. | |||
Unfortunately, the root version '''must''' be specified in each module's POM in the <parent> section, so on version upgrade, all module POM xml files must be kept in sync. [[nort]] does that. | |||
In order to change the version, the version must be changed in the parent POM, and all modules' <parent> sections must be update to reflect the new parent version. | |||
==Independent Versions== | |||
if the version of the modules evolve independently, this can be made clear by specifying the [[#The_Parent_POM|parent POM]] version to be 0, and have each [[#The_Module_POM|module POM]] specify its module's version, independently. The most flexible versioning mechanism is one that defines the component module versions, as system properties, in the parent POM, in the <properties> section. Everywhere else, the modules' version are specified using the such-defined system properties: | |||
===Parent pom.xml=== | |||
<pre> | |||
... | |||
<version>0</version> | |||
... | |||
<properties> | |||
<module.A.version>1.0.1</module.A.version> | |||
<module.B.version>77-SNAPSHOT-7</module.B.version> | |||
<module.release.version>2.1-FINAL</module.release.version> | |||
</properties> | |||
<modules> | |||
<module>A</module> | |||
<module>B</module> | |||
<module>release</module> | |||
</modules> | |||
... | |||
</pre> | |||
===Sub-module pom.xml=== | |||
<pre> | |||
... | |||
<parent> | |||
<groupId>my.example.group</groupId> | |||
<artifactId>my-project</artifactId> | |||
<version>0</version> | |||
</parent> | |||
<artifactId>my-project-A</artifactId> | |||
<version>${module.A.version}</version> | |||
... | |||
</pre> | |||
This convention works well when using the assembly plugin and building a [[Building a Maven Complex Release Artifact|complex Maven release artifact]]. | |||
However, maintaining independent versions for modules of a project may be more complicated than necessary. Use this option only when you have a good reason. | |||
=Module Names, Directories and ArtifactIDs= | |||
Keep the module names, and their corresponding directories, which must be identical with the module names, as simple as possible. They need to make sense only in the context of the project. | |||
However, the artifactId is publicly shipped, so it may make sense to name it more descriptively. For example, in the "events" project case, the modules are "api", "core", etc. However, the corresponding artifactIds are "events-api", "events-core", etc. | |||
==Group ID and Parent/Children Module Relationship== | |||
{{Internal|Maven_Concepts#Group_ID_and_Parent-Children_Module_Relationship|Group ID and Parent/Children Module Relationship}} | |||
=POM Structure= | |||
==The Parent POM== | |||
A multi-module project is defined by a ''parent'' POM referencing one or more submodules. The parent POM file resides in the project root. The essential elements are the packaging, which is of type "pom", and the list of modules. | |||
<pre> | <pre> | ||
<project> | <project> | ||
... | |||
<groupId>io.example</groupId> | |||
<artifactId>user-friendly-name</artifactId> | |||
<version>...</version> | |||
<packaging>pom</packaging> | |||
... | ... | ||
<modules> | <modules> | ||
<module> | <module>A</module> | ||
<module> | <module>B</module> | ||
<module>release</module> | |||
</modules> | </modules> | ||
... | ... | ||
Line 22: | Line 121: | ||
</pre> | </pre> | ||
The <span id="pom_packaging_example">"pom" packaging</span> indicates that the single purpose of this (top-level) project is to provide a container Project Object Model. | |||
The '''group ID''' will be shared with the modules. | |||
=The | The '''artifact ID''' does not really matter, it can be conventionally set to "maven-root". However, if the project is imported in IntelliJ IDEA, the IDE will use this value as the name of the project, so from this perspective, it makes sense to use a unique, user-friendly name. If want your project to be known as "events", name the parent project artifact ID "events". | ||
<blockquote style="background-color: Gold; border: solid thin Goldenrod;"> | |||
:<br>The root's <artifactId> must not coincide with any of its module's <artifactId>, otherwise Maven will complain with "Project '...' is duplicated in the reactor".<br><br> | |||
</blockquote> | |||
For considerations on the '''version''', see "[[#Modules_and_Versions|Modules and Versions]]" section. Most common choice is to go with version "0", as the version of various components will be controlled independently. | |||
Each <tt><module></tt> element corresponds to a ''subdirectory'' of the top level project directory. Maven will look into these subdirectories for <tt>pom.xml</tt> files, and it will add the modules to the list of Maven projects included in a build. Each module will have its own independent source hierarchy. | |||
The rest of the parent POM includes settings to be inherited by all modules. This is where common plug-ins ([[Maven_pom.xml#.3CpluginManagement.3E|<pluginManagement>]]) and dependencies ([[Maven_pom.xml#.3CdependencyManagement.3E|<dependencyManagement>]]) should be declared. | |||
==The Module POM== | |||
The central element of a module POM, which designates it as a module of a larger project, is the <parent> element, which specifies the coordinates (groupId, artifactId and version) of the parent. Since we recommend a conventional value for the parent's version ("0"), the parent section should look similar to: | |||
<pre> | |||
<project> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>...</groupId> | |||
<artifactId>...</artifactId> | |||
<version>0</version> | |||
</parent> | |||
<artifactId>my-artifact-id</artifactId> | |||
... | |||
</project> | |||
</pre> | |||
Note that a module's <project> element does not need to contain a <groupId>, as it is inherited from the parent, and thus redundant. It is logical for modules to share their groupID with the parent. | |||
However, the <artifactID> must be present, as it uniquely identifies the module. | |||
Depending on [[#Modules_and_Versions|the versioning model in use]], the version may not be specified (in which case the modules inherits the parent's version), or it is specified, and that dictates the version of the module, independently of other modules. | |||
= | =Multi-Module Projects and IntelliJ IDEA= | ||
Create the POM files first, then import recursively in IntelliJ. |
Latest revision as of 23:52, 27 February 2017
External
- Guide to Working with Multiple Modules https://maven.apache.org/guides/mini/guide-multiple-modules.html
- A multi-module project http://books.sonatype.com/mvnex-book/reference/multimodule.html
Internal
Overview
For guidelines on when it is appropriate to use modules, and when separate projects, see "When We Should Use Modules ?" section.
The Reactor
When We Should Use Modules?
Two major benefits of a multi-module project are that all the parts can be built with a single command, and Maven handles the correct build order.
Modules and Versions
Different modules of the same project can have different versions, or they can all share the parent's version.
Single Module
When a project consists of a single (implicit) module, whose POM is the only POM of the project, the version is given by the <version> element of the POM file.
Lockstep Versions
This model is appropriate when all modules maintain a common version. This model is simpler, conceptually, than "Independent Versions", described below.
The common version is specified in the parent POM, as the main <version> element. The module may declare literally the same version in their <version> elements, but that is not absolutely necessary. If the <version> element is not explicitly specified in the module's POM, it defaults to ${project.version}, which read its value from the root POM <version> element.
Unfortunately, the root version must be specified in each module's POM in the <parent> section, so on version upgrade, all module POM xml files must be kept in sync. nort does that.
In order to change the version, the version must be changed in the parent POM, and all modules' <parent> sections must be update to reflect the new parent version.
Independent Versions
if the version of the modules evolve independently, this can be made clear by specifying the parent POM version to be 0, and have each module POM specify its module's version, independently. The most flexible versioning mechanism is one that defines the component module versions, as system properties, in the parent POM, in the <properties> section. Everywhere else, the modules' version are specified using the such-defined system properties:
Parent pom.xml
... <version>0</version> ... <properties> <module.A.version>1.0.1</module.A.version> <module.B.version>77-SNAPSHOT-7</module.B.version> <module.release.version>2.1-FINAL</module.release.version> </properties> <modules> <module>A</module> <module>B</module> <module>release</module> </modules> ...
Sub-module pom.xml
... <parent> <groupId>my.example.group</groupId> <artifactId>my-project</artifactId> <version>0</version> </parent> <artifactId>my-project-A</artifactId> <version>${module.A.version}</version> ...
This convention works well when using the assembly plugin and building a complex Maven release artifact.
However, maintaining independent versions for modules of a project may be more complicated than necessary. Use this option only when you have a good reason.
Module Names, Directories and ArtifactIDs
Keep the module names, and their corresponding directories, which must be identical with the module names, as simple as possible. They need to make sense only in the context of the project.
However, the artifactId is publicly shipped, so it may make sense to name it more descriptively. For example, in the "events" project case, the modules are "api", "core", etc. However, the corresponding artifactIds are "events-api", "events-core", etc.
Group ID and Parent/Children Module Relationship
POM Structure
The Parent POM
A multi-module project is defined by a parent POM referencing one or more submodules. The parent POM file resides in the project root. The essential elements are the packaging, which is of type "pom", and the list of modules.
<project> ... <groupId>io.example</groupId> <artifactId>user-friendly-name</artifactId> <version>...</version> <packaging>pom</packaging> ... <modules> <module>A</module> <module>B</module> <module>release</module> </modules> ... </project>
The "pom" packaging indicates that the single purpose of this (top-level) project is to provide a container Project Object Model.
The group ID will be shared with the modules.
The artifact ID does not really matter, it can be conventionally set to "maven-root". However, if the project is imported in IntelliJ IDEA, the IDE will use this value as the name of the project, so from this perspective, it makes sense to use a unique, user-friendly name. If want your project to be known as "events", name the parent project artifact ID "events".
The root's <artifactId> must not coincide with any of its module's <artifactId>, otherwise Maven will complain with "Project '...' is duplicated in the reactor".
For considerations on the version, see "Modules and Versions" section. Most common choice is to go with version "0", as the version of various components will be controlled independently.
Each <module> element corresponds to a subdirectory of the top level project directory. Maven will look into these subdirectories for pom.xml files, and it will add the modules to the list of Maven projects included in a build. Each module will have its own independent source hierarchy.
The rest of the parent POM includes settings to be inherited by all modules. This is where common plug-ins (<pluginManagement>) and dependencies (<dependencyManagement>) should be declared.
The Module POM
The central element of a module POM, which designates it as a module of a larger project, is the <parent> element, which specifies the coordinates (groupId, artifactId and version) of the parent. Since we recommend a conventional value for the parent's version ("0"), the parent section should look similar to:
<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>...</groupId> <artifactId>...</artifactId> <version>0</version> </parent> <artifactId>my-artifact-id</artifactId> ... </project>
Note that a module's <project> element does not need to contain a <groupId>, as it is inherited from the parent, and thus redundant. It is logical for modules to share their groupID with the parent.
However, the <artifactID> must be present, as it uniquely identifies the module.
Depending on the versioning model in use, the version may not be specified (in which case the modules inherits the parent's version), or it is specified, and that dictates the version of the module, independently of other modules.
Multi-Module Projects and IntelliJ IDEA
Create the POM files first, then import recursively in IntelliJ.