Maven - Guide to Working with Multiple Modules

Why Multi Module System in Maven

Imagine you are working on a project based upon a traditional 3 layered architecture, in which the layers are named presentation, business and integration. Of course, you want each layer to be independent of all the other layers and so you want to produce one artifact for each one. Following the Maven norm, you will need to have one project for each layer. Hence, your setup should look like this:
Each project is depending on other project.

sample project structure

So to compile your presentation project, you would first need to compile the business project. But wait, the business project depends upon the integration project so it should be compiled first. Ok,
I thought Maven was simple. Of course, Maven offers a solution to this problem in the form of a multi-modules project.
A multi-modules project is a very particular type of project - it doesn't produce any artifact and is composed of several other projects known as modules. When you run a command on the project, it will execute it on all of its children projects. Even better, Maven is able, through its reactor component (don't worry about it for now), to discover the correct execution order and to detect circular dependencies. So let's apply this solution to the last example. Your project should have the following structure at the end of this lesson:

Multi module structure in maven

First, create a new directory named after your project, something like myproject (original isn't it?). Now let's write the pom file for your multi-modules 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/xsd/maven-4.0.0.xsd">

	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javavillage</groupId>
	<artifactId>MyParent</artifactId>
	<version>4.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Parent with Multi modules</name>
	<modules>
		<module>Presentaion</module>
		<module>Business</module>
		<module>Integration</module>
	</modules>
	<dependencies>
		<dependency>
			<groupId>com.village</groupId>
			<artifactId>Presentation</artifactId>
			<version>${version}</version>
		</dependency>
		<dependency>
			<groupId>com.village</groupId>
			<artifactId>BusinessLayer</artifactId>
			<version>${version}</version>
		</dependency>
		<dependency>
			<groupId>com.village</groupId>
			<artifactId>IntegrationLayer</artifactId>
			<version>${version}</version>
		</dependency>
	</dependencies>
</project>

As you can see, there is nothing very complex in this pom file. It is a normal parent project's pom file, which was introduced in the lesson [todo : link]. Only, this time there is something new: the modules section. The modules section allows you to declare the child modules of a parent project, hence the name multi-modules project. Modules are regular Maven projects which must be located under a subdirectory so the parent project can retrieve them easily.
Just this is an example to understand that how multi modules with parent will help.

Let's look in to Practical, How can we configure as multi modules.


When Maven is executed against a project with submodules, Maven first loads the parent POM and locates all of thesubmodule POMs. Maven then puts all of these project POMs into something called the Maven Reactor which analyzes the dependencies between modules. The Reactor takes care of ordering components to ensure that interdependent modules are compiled and installed in the proper order.
Below Steps required for Multi Module
1. Project structure will not support flat directory. It should be like below.
  • Modules are in Components folder
  • Parent folder inside Core
  • Core and components are in 201-Branch folder. This is the structure we need to follow.

folder structure in svn or cvs for multi module

2. Required changes for parent
  • a. Packaging should be pom
<packaging>pom</packaging>


  • b. SCM locations should be till 201-BRANCH and modules should include as per below: It should be main directory
<scm>
	<connection>scm:svn:http://village.com/svn/branches/201-BRANCH</connection>
	<developerConnection>scm:svn:http://village.com/svn/branches/201-BRANCH</developerConnection>
	<url>http://village.com/svn/branches/201-BRANCH</url>
</scm>
<modules>
	<module>../../Components/Presentation</module>
	<module>../../Components/Business</module>
	<module>../../Components/Integration</module>
</modules>


  • c. Required plugins for parent pom to perform maven release
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-release-plugin</artifactId>
	<version>2.4.1</version>
	<configuration>
		<autoVersionSubmodules>true</autoVersionSubmodules>
		<preparationGoals>clean install</preparationGoals>
	</configuration>
</plugin>
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-scm-plugin</artifactId>
	<version>1.8.1</version>
</plugin>
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>cobertura-maven-plugin</artifactId>
	<version>2.5.2</version>
</plugin>


3. Required changes for modules
  • a. Changes for Presentation component
<modelVersion>4.0.0</modelVersion>
<groupId>com.village</groupId>
<artifactId>Presentation</artifactId>
<version>2.201-SNAPSHOT</version>
<name>PresentationLayer</name>
<packaging>jar</packaging>
<parent>
	<groupId>com.village</groupId>
	<artifactId>parent</artifactId>
	<version>2.201-SNAPSHOT</version>
</parent>
<scm>
	<connection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Presentation</connection>
	<developerConnection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Presentation
							</developerConnection>
	<url>http://village.com/svn/branches/201-BRANCH/Components/Presentation</url>
</scm>


  • b. Changes for Business component
<modelVersion>4.0.0</modelVersion>
<groupId>com.village</groupId>
<artifactId>Business</artifactId>
<version>2.201-SNAPSHOT</version>
<name>BusinessLayer</name>
<packaging>jar</packaging>
<parent>
	<groupId>com.village</groupId>
	<artifactId>parent</artifactId>
	<version>2.201-SNAPSHOT</version>
</parent>
<scm>
	<connection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Business </connection>
	<developerConnection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Business
					</developerConnection>
	<url>http://village.com/svn/branches/201-BRANCH/Components/Business</url>
</scm>

  • c. Changes for Intergration component
<modelVersion>4.0.0</modelVersion>
<groupId>com.village</groupId>
<artifactId>Integration</artifactId>
<version>2.201-SNAPSHOT</version>
<name>IntegrationLayer</name>
<packaging>jar</packaging>
<parent>
	<groupId>com.village</groupId>
	<artifactId>parent</artifactId>
	<version>2.201-SNAPSHOT</version>
</parent>
<scm>
	<connection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Integration</connection>
	<developerConnection>scm:svn:http://village.com/svn/branches/201-BRANCH/Components/Integration
						</developerConnection>
	<url>http://village.com/svn/branches/201-BRANCH/Components/Integration</url>
</scm>


Note: For Modules
  • a. For modules no need to specify the version, that will be picked based on parent version and maven release. While doing maven release based on the updates that will committed by the respected Build tools(Jenkins/Hudson).
<version>2.201-SNAPSHOT</version>    // Not required for modules

  • b. Parent version for sub modules pom.xml also will be updated based on release..
<parent>
	<groupId>com.village</groupId>
	<artifactId>parent</artifactId>
	<version>2.201-SNAPSHOT</version>
	//This will be updated by the maven release for modules
</parent>
  • Version is mandatory for parent in modules, otherwise will get an error version is missing for parent in module.
  • After maven release on parent, directly it will be updated in modules for parent without snapshot. Because snapshot will not be there for maven release. This snapshot initial configuration will give until we start maven release on parent.
  • c. Scm locations will be as per the SVN locations for modules, it is not like parent pom. For parent pom we have to specify till 201-BRANCH that means main directory location.
Parent:
SVN Location:http://village.com/svn/branches/201-BRANCH/core/parent
SCM location:http://village.com/svn/branches/201-BRANCH
Modules:
SVN Location:http://village.com/svn/branches/201-BRANCH/Components/Integration
SCM location:http://village.com/svn/branches/201-BRANCH/Components/Integration
4. Jenkins Setup for parent project:
Need to add both locations for core and Components

configuration setup for multimodule in jenkins or hudson

Root pom location needs to specify like below(parent/pom.xml), because SVN location we have specified till core(find in above screen shot).

Jenkins build for multimodule for parent pom

Note: Create only job for parent, don't create jobs for modules also. Because:
  • Parent will have snapshots and releases for modules also.
  • If you have jobs for parent and modules, while running test cases for module job and parent module job test cases will fail if runs at time because of ports. Have only one job in Jenkins for parent for one branch, if we are going with multi modules.