Maven - Multi-Module Projects
Reading material
- https://maven.apache.org/pom.html#Aggregation
- https://www.baeldung.com/maven-multi-module
- https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
Parent pom
A project with modules is known as a multi-module, or aggregator project. Modules are projects that this POM lists, and are executed as a group. A pom
packaged project may aggregate the build of a set of projects by listing them as modules, which are relative paths to the directories or the POM files of those projects.
You do not need to consider the inter-module dependencies yourself when listing the modules; i.e. the ordering of the modules given by the POM is not important. Maven will topologically sort the modules such that dependencies are always build before dependent modules.
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<packaging>pom</packaging>
<modules>
<module>my-project</module>
<module>another-project</module>
<module>third-project/pom-example.xml</module>
</modules>
</project>
By setting the packaging to pom type, we declare that the project will serve as a parent or an aggregator; it won’t produce further artifacts.
<packaging>pom</packaging>
In the parent-project‘s pom.xml, all the submodules are added inside the modules section:
<modules>
<module>core</module>
<module>service</module>
<module>webapp</module>
</modules>
In the individual submodules’ pom.xml, it will add the parent-project in the parent section:
<parent>
<groupId>com.my.company</groupId>
<artifactId>design-pattern-samples</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
To build the project, go to the root of the parent project and run this:
mvn package
or
mvn verify
How to make one module depend on another module?
Some of these child modules may have inter-dependencies.
A: parent
B: child1
C: child2
C
can have a dependency on B
.
A
pom.xml
<groupId>AAA</groupId>
<artifactId>A</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>B</module>
<module>C</module>
</modules>
B
pom.xml
<groupId>AAA</groupId>
<artifactId>B</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>A</artifactId>
<groupId>AAA</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
In C
’s pom file, specify the dependency like this:
<groupId>AAA</groupId>
<artifactId>C</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>A</artifactId>
<groupId>AAA</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>A</groupId>
<artifactId>B</artifactId>
<version>${project.parent.version}</version>
<type>jar</type>
</dependency>
...
Enable Dependency Management in Parent Project
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
Dependency management is a mechanism for centralizing the dependency information for a multi-module parent project and its children.
When you have a set of projects or modules that inherit a common parent, you can put all the required information about the dependencies in the common pom.xml file. This will simplify the references to the artifacts in the child POMs.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.16</version>
</dependency>
//...
</dependencies>
</dependencyManagement>
By declaring the spring-core version in the parent, all submodules that depend on spring-core can declare the dependency using only the groupId and artifactId, and the version will be inherited:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
//...
</dependencies>
Moreover, you can provide exclusions for dependency management in parent’s pom.xml, so that specific libraries will not be inherited by child modules:
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
If a child module needs to use a different version of a managed dependency, you can override the managed version in the child’s pom.xml file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.30.RELEASE</version>
</dependency>
Inheritance v. Aggregation
- Inheritance and aggregation create a nice dynamic to control builds through a single, high-level POM. You often see projects that are both parents and aggregators.
- For example, the entire Maven core runs through a single base POM
org.apache.maven:maven
, so building the Maven project can be executed by a single command:mvn compile
. - However, an aggregator project and a parent project are both POM projects, they are not one and the same and should not be confused.
- A parent POM project may be inherited from (by child projects) - but need not necessarily have - any modules that it aggregates.
- Conversely, a parent POM project may aggregate projects that do not inherit from it.
Common issues when dealing with multi-module projects
cannot access class
Use Maven - maven-compiler-plugin with the same configuration in all of the sub-modules. Do not depend on the default behavior. What happens if we don’t? We will run into error like this:
Maven java compile error can not access CommonClassA
This class is expected to be compiled in a sub-module and is expected to be accessed by another class in another sub-module. If the versions of jdk, release, etc. don’t match up exactly, there will be errors.
package does not exist
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.600 s
[INFO] Finished at: 2025-07-06T19:35:22-04:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project my-java-solutions: Compilation failure
[ERROR] /home/explorer436/Downloads/GitRepositories/programming-playground/java-playground/my-implementations/my-java-solutions/src/main/java/com/my/company/hackerrank/SimpleArraySum.java:[3,33] package com.my.company.streamsapi does not exist
[ERROR]
[ERROR] -> [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/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <args> -rf :my-java-solutions
Failed to read artifact descriptor
https://stackoverflow.com/questions/6642146/maven-failed-to-read-artifact-descriptor
Failed to read artifact descriptor for com.morrislgn.merchandising.common:test-data-utils:jar:0.3b-SNAPSHOT: Could not find artifact com.morrislgn.merchandising:merchandising:pom:0.3b-SNAPSHOT
You can always try mvn -U clean install
-U
forces a check for updated releases and snapshots on remote repositories.