Maven – Dependency Management and Optimization Approach

I recommend this tutorial to you when you already have a Maven multi module project or, when you want to set up a new multi module project directly with a first sign of “optimization” and dependency control. (For this you just need to know how to create a  maven project in your IDE (or with archetypes)) 

During my young career I almost worked in a few projects, in different companies and, furthermore, in different teams in a company. The first thing that comes when I think about the programming practices in this teams is, the bigger and “older” the application gets, the more increases the complexity and the dependencies to other projects, libraries and tools.

One way to handle dependencies is by using Maven. Maven is a very capable tool that can get very complex but it can also stay quite simple. That´s all in the care of the developer.
This little guide will show you a good approach (for me) how to handle your hundreds (or maybe some less 😉 ) dependencies.

The Project

(on github)
For our optimization sample I build a simple multi module project. It has a persistence-module (which will be a jar), a boundary-module (which will be a war) and the mulit-module-parent which will be packaged as a pom and has the two other projects.

I will just place the finished pom.xml – codes here for you, because this is the essential of this small tutorial.

The multi-module-parent

At first let´s think about, why we should build a parent-pom. 

Every dependency you need to use, must be defined with a <groupId> with it´s <artifactId> and a <version>.
(There are still some more attributes that can be added to a dependency but for now this are irrelevant). Now in a “real-world-application” many teams work at different features / modules. Imagine the following Situation

  • Team A: EclipseLink 2.2.0
  • Team B: EclipseLink 2.1.1
  • Team C: EclipseLink 2.2.0

So what could happen: Every team is testing their new features, everything is working fine. But during the build, the pipeline is throwing exceptions.
Dependencies between the different modules are causing this.
For example, the EclipseLink Version of Team B is not supporting the operations called by the module of Team A.
Analyzing and remedy the bug will take a long time because the error message is not meaningful.

DependencyManagement Tag

It is a good approach to control the dependency versions centralized in one pom. This guarantees that every module is using the same version and if we have to change the version (such as upgrade to a newer version) we just have to change one place in the code.

<?xml version="1.0" encoding="UTF-8"?>
<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.javadevcorner</groupId>
    <artifactId>multi-module-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>persistence-module</module>
        <module>boundary-module</module>
    </modules>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.eclipse.persistence</groupId>
                <artifactId>javax.persistence</artifactId>
                <version>2.2.0</version>
            </dependency>  
        </dependencies>
    </dependencyManagement>
</project>

After we have done this we need to remove every <version> tag in the poms of the child modules.
We will need the EclipseLink Dependency only in the persistence-module:

..... 
<dependency>
           <groupId>org.eclipse.persistence</groupId>
           <artifactId>javax.persistence</artifactId>
</dependency>  
.....

That´s all. Now we have a central managed version control over all the dependencies we want to.

Define Versions in Properties

After we introduced the DependencyManagement-Tag there is another thing in the parent pom I don´t like. Let´s look at the different dependencies in more detail.

.....
<dependency>
           <groupId>org.eclipse.persistence</groupId>
           <artifactId>javax.persistence</artifactId>
           <version>2.2.0</version>
</dependency>  
.....

Every dependency has a hardcoded version number. For a small amount of dependencies this is a well done and good approach. For me, I think it is nice to have one place in which we define all the version numbers and just let the dependency reference to them.

Move again to our multi-module-parent and implement as follows.

For this we define a <eclipse.persistence.version> Tag in the <properties> section and reference this attribute by using ${<your_version_attribute>} 

.....
    <properties>
        .....
        <eclipse.persistence.version>2.2.0</eclipse.persistence.version>
    </properties>
    
    <dependencyManagement>
        .....
            <dependency>
                <groupId>org.eclipse.persistence</groupId>
                <artifactId>javax.persistence</artifactId>
                <version>${eclipse.persistence.version}</version>
            </dependency>  
        .....
    </dependencyManagement>
</project>

Replace Project-Versions

During development, some code features are already deploy to the live system. At least from this point you´ll have different SNAPSHOT-Versions. If you bin your module hardcoded to one specific release number there can also be side effects. One simple case could be, that you can not access features from other modules because you refer to an old version of this module.

While we are at this point we can take care of the <groupId> as well. What would happen if you change the groupId of your project. Then you have to replace it in every module. In a project containing for example 100 modules you´ll need a lot of coffee and stamina for this job. Let´s not forget the investment of time for this task.

To prevent both of this problems there are these two pre-defined maven variable:

  • project.version
  • project.groupId

We use them exactly as we used our own variable. Let´s move to the pom-file of our boundary-module.
In this pom.xml we have a reference to the module persistence-module. We modify the dependency to our persistence module with the new learned maven variables:

.....
 <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>persistence-module</artifactId>
            <version>${project.version}</version>
</dependency>
.....

So thanks for reading and have fun with the Maven DependencyManagement.

Feel free to share

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.