Multi Module Dependency Management
Dependency inheritance (explained in previous chapter) is useful when a dependency is required by all child modules. When a dependency is required by some or even many, but not by all modules, then use dependency management feature.
The example code extended-multi
, used in this tutorial, is available
at GitHub Maven Examples. Download the examples as zip and extract it to some location or clone it with git.
In extended-multi
, util
module uses commons-lang3 as dependency and
let’s assume that another module app
also require commons-lang3. Now,
both app/pom.xml
and shared/util/pom.xml
should declare this
dependency. When multiple modules require a dependency then move it the
top-level pom.xml as dependencyManagement
.
To move commons-lang3 to dependency management, first modify the
extended-multi/pom.xml
and following lines
extended-multi/pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
</dependencies>
</dependencyManagement>
The dependency management declaration is dependencies declaration wrapped in dependencyManagement element.
Next, modify app/pom.xml
and add the following to dependencies
element. Notice that version is not specified.
app/pom.xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
Next, modify shared/util/pom.xml
and remove version element from the
commons-lang3 dependency. After modification the dependency is as
follows
shared/util/pom.xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
To use commons-lang3 from app module, modify the greet() method of App.java as follows
app/src/main/java/app/App.java
....
import org.apache.commons.lang3.StringUtils;
public class App {
public String greet(String name) {
StringUtils.trim("dummy");
return Util.join("Hello ", name);
}
....
Now, run mvn test
and project should build successfully.
To summarize, we added the dependency in top level pom.xml as dependencyManagement and referred it in required modules using simpler reference i.e. just groupId + artifactId and without the version.
Dependency Management vs Inheritance
Dependency management
- used when dependency is required by some of the child modules
- declared in parent POM using
dependencyManagement/dependencies/dependency
element - need to refer them in the required child modules using simpler reference i.e. just groupId + artifactId, but without the version
Dependency inheritance, which we explained in the previous tutorial
- used when dependency is required by all child modules
- declared in parent POM using
dependencies/dependency
element - no need to refer them in the child modules as they are inherited by all child modules by default
Plugin Management
Let’s suppose that all modules of extended-app should compile as Java 1.7. One way to do this is configure compiler plugin by adding following snippet to app, util and config POM.
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
Instead, the better approach is to centralize the plugin configuration
using pluginManagement
element in top level POM. To do that, add
following lines to the top level POM extended-multi/pom.xml
extended-multi/pom.xml
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Next, we need to refer the plugin in the required modules. Modify all
module POM, app/pom.xml
, shared/util/pom.xml
and shared/config.pom
and add following lines
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
While referring the plugin in the modules, specify plugin groupId, artifactId and there is no need to repeat the version as well as the configuration as they are inherited from the parent POM.
Child module POM can override the configuration if required. For
example, replace compiler plugin reference in shared/config/pom.xml
as
below
shared/config/pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Run mvn clean test
, app and util module are complied as Java 1.7 where
as config module is complied as Java 1.8. We can investigate the
compiled classes and know Java version
with
$ javap -verbose app/target/test-classes/app/AppTest.class | grep major
$ javap -verbose shared/util/target/test-classes/util/UtilTest.class | grep major
$ javap -verbose shared/config/target/test-classes/config/ConfigServiceTest.class | grep major
## for Java 1.7, output is major version: 51
## for Java 1.8, output is major version: 52
For more complicated examples of Maven Multi Module Project, refer Official Maven Book - Maven By Example.
The next chapter, the concluding part of the tutorial, covers integration of Maven with Eclipse IDE.