Maven Mutli Module

As project grows in size and complexity, it makes sense to split the project into multiple modules. While it is possible to split a project into separate projects and link them as dependencies, it unnecessarily complicates the build process.

When modules are parts of a project, the preferred approach is to structure them as a maven multi module project and delegate the build responsibility completely to Maven.

The example code explained in this tutorial is available at GitHub Maven Examples. Download the examples as zip and extract it to some location or clone the project with

$ git clone git@github.com:maithilish/maven-multi-module-examples.git

 

Simple Multi Module Project

Let’s start with a Simple Multi Module project with just two modules - app and util.

The util module provides a static method that joins multiple strings using Commons Lang library while app module calls the util module static method. Snippet from App.java is shown below

simple-multi/app/src/main/java/app/App.java

public class App {    

    public String greet(String name) {
        return Util.join("Hello ", name);
    }
}

To build the project, go to the extracted directory and run

$ cd simple-multi
$ mvn test

Maven builds both the modules in proper order, runs tests and outputs nice little summary.

Maven Multi Module Project Build Summary

Structure of multi module project

The layout of Simple Multi is

Maven Multi Module Project Simple Multi Layout

The directory simple-multi is the top directory of the multi module project. It contains the parent POM also known as top-level POM, but it doesn’t contain any source folder.

Along with parent POM, the top level directory also contains two sub folders – app and util. These module folders are regular maven projects with source directories and pom.xml.

The parent module POM slightly differs from the regular POM and let’s see what are they.

 
 

Top Level POM

Maven Multi Module Project requires a parent POM at the project’s top level directory. The contents of the file is

simple-multi/pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.codetab</groupId>
  <artifactId>simple-multi</artifactId>
  <version>1.0</version>
  <packaging>pom</packaging>

  <modules>
      <module>app</module>
      <module>util</module>
  </modules>

</project>

It defines project coordinates - groupId, artifactId and version - as in normal project, but the packaging element is specified as pom type instead of usual jar or war. Since top level project doesn’t contain any source directory, we set the packaging as pom. The modules/module elements add the modules - app and util.

To summarize, top level POM specifies packaging type as pom and lists all sub modules.

Maven Reactor

While declaring the modules in parent POM there is no need to bother about their ordering as Maven uses software component called reactor to properly order the modules. In simple-multi, maven first builds util and then app module as app depends on util.

 
 

Module POM

Next, let’s explore directory of the util module. It contains normal source directory. Along with source directory, each module should define its own pom.xml and the contents of util/pom.xml is as below

util/pom.xml

<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/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <parent>
       <groupId>org.codetab</groupId>
       <artifactId>simple-multi</artifactId>
       <version>1.0</version>
   </parent>

   <artifactId>util</artifactId>

   <dependencies>
       <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-lang3</artifactId>
           <version>3.6</version>
       </dependency>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
           <scope>test</scope>
       </dependency>
   </dependencies>

</project>

The parent element refers the parent using its coordinates. The artifact id of the module is specified with artifactId element and there is no need to specify groupId and version as they are derived from the parent. The dependencies/dependency block defines the dependencies of the module - commons-lang3 and junit.

Next, let’s see the app/pom.xml and except for dependencies it is similar to util/pom.xml. The app module uses methods from util module and for this, the app/pom.xml specifies util as dependency. The dependencies block is show below

app/pom.xml

....
<dependencies>
    <dependency>
        <groupId>org.codetab</groupId>
        <artifactId>util</artifactId>
        <version>1.0</version>
    </dependency>
    ....
</dependencies>

To summarize, the module is nothing but normal maven project directory with only exception being pom.xml and its pom.xml we specify,

  • parent coordinates in parent element
  • for module coordinates, we specify only the artifactId. The groupId and version are not specified as they are derived from parent coordinates
  • when one module depends on another module, then specify it as dependency

In the next tutorial, we extend the simple-multi example and convert it into a hierarchical multi module with multiple parent POM.