Maven is the de facto tool for JEE application build and dependency management. Most developers are familiar with how to use it, mainly for its artifact dependency management.
Simpliest Setup
A simple maven 2 pom looks like below
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.kole.component</groupId>
<artifactId>example</artifactId>
<packaging>jar</packaging>
<name>example component</name>
<version>1.0.0-SNAPSHOT</version>
<description>example component</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</project>
Usually this will sit under a directory structure of
/project
-/src/main/java
-/src/test/java
-pom.xml
Modular Setup
In most real world projects, there are usually more than 1 software modules within each applications. In a standard JEE project, the application are created as a combination of components/utilities where each of them is built to satisfy a specific requirements.
Therefore, a JEE application is most likely to consist of
- utility-component
- core-component
- service-component1
- service-component2
- presentation-component
To make the problem even more complex, with a large scale project, it is common practise to have several small teams looking after the development of each component. To minimise dependencies within each team, it is best practice to breakup the component in the following build artifacts
- component-api
- component-impl
- component-mock
Furthermore, to ensure the success of the project, the following areas needed to be clearly strategised:
- Maintain external library dependencies, to remove issues caused by conflicting library versions
- Maintain component dependencies, to remove circular dependencies
- Implement continuous integration and release process
So, let’s look at how we can utilise maven to help us achieve the goals
POM Inheritance
It is possible to define a parent pom that is inherited by all the build artifacts within the application. And within the parent pom, we can define a <dependencyManagement> section to specify the default versions for all of the required library dependencies. Here is an example:
Parent pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.kole.component</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<name>component parent pom</name>
<version>1.0.0-SNAPSHOT</version>
<description>component parent pom</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Children pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kole.component</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.kole.component</groupId>
<artifactId>example1</artifactId>
<!-- no component version specified here -->
<packaging>jar</packaging>
<name>component example1</name>
<description>component example1</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!-- No library dependency version specified here-->
</dependency>
</dependencies>
</project>
From the above example, we can see that
- The component version is inherited from the parent
- The library version is controlled by the parent pom, hence eliminating the possible conflicting library dependencies
Directory Structure
By taking advantage of the maven release plugin, it is possible to release the whole component as one version, tagging all the sub modules in one go. The following is one example
/utility-component
-/utility-api
-pom.xml (child pom)
-/utility-impl
-pom.xml (child pom)
-pom.xml (parent pom)
The above structure allows us to perform maven release:prepare release:perform on the parent pom level to control all of the child pom’s version number.
At an application level, then it is possible to create an assembly pom to draw in released components to create the final artifact.
Continuous Integration
The final issue to take care of is how do we enforce continuous integrate at all time. Since within the application and components pom, it is depending on a ranged released version of another components, CI should always be testing changes committed within the component ONLY, but will pick up the next release as soon as its made available. To configure a ranged dependency, here is an example
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[4.0.0-4.1.0)</version>
<!-- includes the latest 4.0.x version release -->
</dependency>
To summarise, the examples showed how to implement a SDLC strategy by using Maven that enables component releases. The key points are
- Implement a parent pom the controls the component versions and library dependencies
- Setup the correct directory structure that simplifies a release process
- Implement versioning strategy and version dependency strategy to minimise efforts to enable continuous integration.



It was interesting to read this article and I hope to read a new article about this subject in your site in the near time.