8 min read

(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:

org.codehaus.jedijedi-${jdk.version} ${jedi.version}

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

src/main/resource **/*-${environment}.xml

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:

postgresqlpostgresql9.1-901.jdbc4runtimemysqlmysql-connector-java5.1.25runtimeorg.hsqldbhsqldb2.3.0runtime

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:

${effective.groupId} ${effective.artifactId} ${effective.version}

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:

org.springframeworkspring-core3.2.3.RELEASEcompileorg.codehaus.jedijedi-jdk6 3.0.5compilepostgresqlpostgresql9.1-901.jdbc4 compile

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:

PRODPROD postgresql postgresql 9.1-901.jdbc4 jdk6true

Or:

DEVDEV org.hsqldb hsqldb 2.3.0 jdk5false

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:

PRODPROD postgresql postgresql 9.1-901.jdbc4 jdk6true

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 [-f ] [-s ]

  • Otherwise, include profiles and properties within the POM

    mvn [-f ] [-P ] [-s ]

  • Otherwise, launch Maven with the properties in command lines

    mvn [-f ] [-s ] -D= -D= (...) -D=

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:



Subscribe to the weekly Packt Hub newsletter

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here