Dynamic POM

Exclusive offer: get 50% off this eBook here
Apache Maven Dependency Management

Apache Maven Dependency Management — Save 50%

Manage your Java and JEE project dependencies with ease with this hands-on guide to Maven with this book and ebook

$20.99    $10.50
by Jonathan Lalou | November 2013 | Games Open Source

This article is written by Jonathan Lalou author of the book Apache Maven Dependency Management. As a disclaimer, beware the following example is used for its pedagogical interest and may fit some situations, but does not match best practices for many other projects. Among other theoretical and practical reasons, common IDEs have some difficulties to support full dynamic POMs.

(For more resources related to this topic, see here.)

Case study

Our project meets the following requirements:

  • It depends on org.codehaus.jedi:jedi-XXX:3.0.5. Actually, the XXX is related to the JDK version, that is, either jdk5 or jdk6.
  • The project is built and run on three different environments: PRODuction, UAT, and DEVelopment
  • The underlying database differs owing to the environment: PostGre in PROD, MySQL in UAT, and HSQLDB in DEV.
  • Besides, the connection is set in a Spring file, which can be spring-PROD.xml, spring-UAT.xml, or spring-DEV.xml, all being in the same src/main/resource folder.

The first bullet point can be easily answered, using a jdk-version property.

The dependency is then declared as follows:

<dependency> <groupId>org.codehaus.jedi</groupId> <!--For this dependency two artifacts are available, one for jdk5 or and a second for jdk6--> <artifactId>jedi-${jdk.version}</artifactId> <version>${jedi.version}</version> </dependency>

Still, the fourth bullet point is resolved by specifying a resource folder:

<resources> <resource> <directory>src/main/resource</directory> <!--include the XML files corresponding to the environment: PROD, UAT, DEV. Here, the only XML file is a Spring configuration one. There is one file per environment--> <includes> <include> **/*-${environment}.xml </include> </includes> </resource> </resources>

Then, we will have to run Maven adding the property values using one of the following commands:

  • mvn clean install –Denvironment=PROD –Djdk.version=jdk6
  • mvn clean install –Denvironment=DEV –Djdk.version=jdk5

By the way, we could have merged the three XML files as a unique one, setting dynamically the content thanks to Maven's filter tag and mechanism.

The next point to solve is the dependency to actual JDBC drivers.

A quick and dirty solution

A quick and dirty solution is to mention the three dependencies:

<!--PROD --> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.1-901.jdbc4</version> <scope>runtime</scope> </dependency> <!--UAT--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> <scope>runtime</scope> </dependency> <!--DEV--> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.3.0</version> <scope>runtime</scope> </dependency>

Anyway, this idea has drawbacks. Even though only the actual driver (org. postgresql.Driver, com.mysql.jdbc.Driver, or org.hsqldb.jdbcDriver as described in the Spring files) will be instantiated at runtime, the three JARs will be transitively transmitted—and possibly packaged—in a further distribution.

You may argue that we can work around this problem in most of situations, by confining the scope to provided, and embed the actual dependency by any other mean (such as rely on an artifact embarked in an application server); however, even then you should concede the dirtiness of the process.

A clean solution

Better solutions consist in using dynamic POM. Here, too, there will be a gradient of more or less clean solutions.

Once more, as a disclaimer, beware of dynamic POMs! Dynamic POMs are a powerful and tricky feature of Maven. Moreover, modern IDEs manage dynamic POMs better than a few years ago. Yet, their use may be dangerous for newcomers: as with generated code and AOP for instance, what you write is not what you execute, which may result in strange or unexpected behaviors, needing long hours of debug and an aspirin tablet for the headache. This is why you have to carefully weigh their interest, relatively to your project before introducing them.

With properties in command lines

As a first step, let's define the dependency as follows:

<!-- The dependency to effective JDBC drivers: PostGre, MySQL or HSQLDB--> <dependency> <groupId>${effective.groupId}</groupId> <artifactId> ${effective.artifactId} </artifactId> <version>${effective.version}</version> </dependency>

As you can see, the dependency is parameterized thanks to three properties: effective.groupId, effective.artifactId, and effective.version. Then, in the same way we added earlier the –Djdk.version property, we will have to add those properties in the command line, for example,:

mvn clean install –Denvironment=PROD –Djdk.version=jdk6 \ -Deffective.groupId=postgresql \ -Deffective.artifactId=postgresql \ -Deffective.version=9.1-901.jdbc4

Or add the following property

mvn clean install –Denvironment=DEV –Djdk.version=jdk5 \ -Deffective.groupId=org.hsqldb \ -Deffective.artifactId=hsqldb \ -Deffective.version=2.3.0

Then, the effective POM will be reconstructed by Maven, and include the right dependencies:

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.2.3.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.codehaus.jedi</groupId> <artifactId>jedi-jdk6</artifactId> <version>3.0.5</version> <scope>compile</scope> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.1-901.jdbc4</version> <scope>compile</scope> </dependency> </dependencies>

Yet, as you can imagine, writing long command lines like the preceding one increases the risks of human error, all the more that such lines are "write-only". These pitfalls are solved by profiles.

Profiles and settings

As an easy improvement, you can define profiles within the POM itself. The profiles gather the information you previously wrote in the command line, for example:

<profile> <!-- The profile PROD gathers the properties related to the environment PROD--> <id>PROD</id> <properties> <environment>PROD</environment> <effective.groupId> postgresql </effective.groupId> <effective.artifactId> postgresql </effective.artifactId> <effective.version> 9.1-901.jdbc4 </effective.version> <jdk.version>jdk6</jdk.version> </properties> <activation> <!-- This profile is activated by default: in other terms, if no other profile in activated, then PROD will be--> <activeByDefault>true</activeByDefault> </activation> </profile>

Or:

<profile> <!-- The profile DEV gathers the properties related to the environment DEV--> <id>DEV</id> <properties> <environment>DEV</environment> <effective.groupId> org.hsqldb </effective.groupId> <effective.artifactId> hsqldb </effective.artifactId> <effective.version> 2.3.0 </effective.version> <jdk.version>jdk5</jdk.version> </properties> <activation> <!-- The profile DEV will be activated if, and only if, it is explicitly called--> <activeByDefault>false</activeByDefault> </activation> </profile>

The corresponding command lines will be shorter:

mvn clean install

(Equivalent to mvn clean install –PPROD)

Or:

mvn clean install –PDEV

You can list several profiles in the same POM, and one, many or all of them may be enabled or disabled.

Nonetheless, multiplying profiles and properties hurts the readability. Moreover, if your team has 20 developers, then each developer will have to deal with 20 blocks of profiles, out of which 19 are completely irrelevant for him/her. So, in order to make the thing smoother, a best practice is to extract the profiles and inset them in the personal settings.xml files, with the same information:

<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/ SETTINGS/1.0.0 http://maven.apache.org/xsd/ settings-1.0.0.xsd"> <profiles> <profile> <id>PROD</id> <properties> <environment>PROD</environment> <effective.groupId> postgresql </effective.groupId> <effective.artifactId> postgresql </effective.artifactId> <effective.version> 9.1-901.jdbc4 </effective.version> <jdk.version>jdk6</jdk.version> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> </profiles> </settings>

Dynamic POMs – conclusion

As a conclusion, the best practice concerning dynamic POMs is to parameterize the needed fields within the POM. Then, by order of priority:

  • Set an enabled profile and corresponding properties within the settings.xml.

    mvn <goals> \ [-f <pom_Without_Profiles.xml> \] [-s <settings_With_Enabled_Profile.xml>]

  • Otherwise, include profiles and properties within the POM

    mvn <goals> \ [-f <pom_With_Profiles.xml> \] [-P<actual_Profile> \] [-s <settings_Without_Profile.xml>]

  • Otherwise, launch Maven with the properties in command lines

    mvn <goals> \ [-f <pom_Without_Profiles.xml> \] [-s <settings_Without_Profile.xml>] -D<property_1>=<value_1> \ -D<property_2>=<value_2> \ (...) -D<property_n>=<value_n>

Summary

In this article we learned about Dynamic POM. We saw a case study and also saw its quick and easy solutions.

Resources for Article:


Further resources on this subject:


Apache Maven Dependency Management Manage your Java and JEE project dependencies with ease with this hands-on guide to Maven with this book and ebook
Published: October 2013
eBook Price: $20.99
Book Price: $34.99
See more
Select your format and quantity:

About the Author :


Jonathan Lalou

Jonathan is an engineer who has been fascinated by new technologies, computer sciences, and the digital world ever since his childhood. As a graduate of the Ecole des Mines–one of the best French polytechnic institutes, Jonathan has more than 13 years of experience in Java and JEE ecosystems.

Jonathan has worked for several global companies and financial institutions–Syred, Philips, Sungard, Ixis CIB, BNP Paribas, Amundi AM–with whom he maintains strong ties and daily contacts. During his career, Jonathan has successfully progressed through many levels of his industry, working as a developer, architect, Scrum master, team leader, and project manager. Now, Jonathan has joined StepInfo (http://www.stepinfo.com/), a high-tech company focused on Java and the sponsor of local JUG and Devoxx, where he works as a project director, trainer, and leader of “expert task forces.”

Jonathan’s skills include advanced knowledge of a wide range of technologies and frameworks: Spring, Hibernate, GWT, Mule ESB, Struts, JSF, Groovy, Android, EJB, JMS, application servers, agile methods, and of course, Apache Maven. Jonathan is available on the cloud… Blog: http://jonathan.lalou.free.fr Twitter: http://twitter.com/john_the_cowboy LinkedIn: http://www.linkedin.com/in/jonathanlalou

Books From Packt


 Apache Maven 2 Effective Implementation
Apache Maven 2 Effective Implementation

 Instant Apache Maven Starter [Instant]
Instant Apache Maven Starter [Instant]

 Apache Maven 3 Cookbook
Apache Maven 3 Cookbook

 Learning Apache Karaf
Learning Apache Karaf

 Instant Apache ActiveMQ Messaging Application Development How-to [Instant]
Instant Apache ActiveMQ Messaging Application Development How-to [Instant]

 Instant Apache Stanbol [Instant]
Instant Apache Stanbol [Instant]

 Instant Apache Camel Messaging System [Instant]
Instant Apache Camel Messaging System [Instant]

 Instant Apache Wicket 6 [Instant]
Instant Apache Wicket 6 [Instant]


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
y
m
z
i
K
X
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software