Tag Archives: maven

Changing Maven POM Versions With Groovy and XSLT

One of the projects I am working on uses Apache Maven for doing builds. Usually, I let the Maven Release plugin take care of all of the version numbering. When I instruct maven to generate a release version or do a branch, it will ask for the new version for each of the artifacts in my project. The project I’m working on has about 15 different artifacts so switching the version numbers all of the time can take a bit of time. Allowing Maven to do this for me makes sense.

This brings me to my latest problem. We needed to change the version of all of our Maven artifacts outside of a release. Instead of incrementing the minor release number we are preparing for a major release (1.x to 2.x). I could do the version change the brute force way but being a programmer, I have strong instincts that prevent me from doing a repeatable monotonous task. Am I lazy? A bit, but I like to call it being efficient. I would rather take an hour and write a small script to do the task for me than take 15 minutes on the brute force approach.

What I needed to do was change all of the occurrences of 1.0-SNAPSHOT to 2.0-SNAPSHOT in all of my pom.xml files. Not only does this need to change for the main artifact but also for any dependencies.


  <groupId>com.chrisdail.project</groupId>
  <artifactId>parent</artifactId>
  <version>1.0-SNAPSHOT</version>

My first attempt to write a script to do this was using Python. There were a few issues I ran into pretty quickly. I do not like most of the standard python libraries for XML parsing. The DOM library has the same issues as the Java DOM library. I just wanted a ‘simple’ XML library. So I decided to use the ElementTree library. I have used it in the past and it is very nice to use. I soon found that this would give me a few problems.

  • ElementTree does not support namespaces well. I wanted to use the findAll() method but it does not support namespaces.
  • Another thing I wanted to do is use full XPath. It is very simple to express finding all versions where the ../groupId = ‘mygroup’ in xpath. XPath seems better than writing this in code

Because of these issues I quickly decided that Groovy may be a better language for this script. Groovy has great XML support using their XmlParser. I actually produced a fully working script using the XmlParser that did exactly what I needed. The only issue with it was that when you write out the XML from Groovy after it was parsed, it was not maintaining the original formatting. I did not want to have the entire formatting of my pom.xml files be changed just for a version change. So this lead me back to XSLT.

I had done a lot of XSLT in my previous job and it really is the best tool for this kind of XML manipulations. It is very easy to preserve the original XML structure and make small modifications to it. The approach is to start with the standard identify stylesheet. This stylesheet essentially produces an exact copy of the original. From there you can add specializations to modify any things you need. Here is the identity stylesheet:


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

To this, I added a template to match the maven version number element where the ../groupId was the group I was concerned with and change the version number to what I desired.


    <xsl:template match="m:version[../m:groupId='com.chrisdail.project']">
		<version>2.0-SNAPSHOT</version>
    </xsl:template>

This 10 line XSLT did all of the processing on the pom.xml file I required. I wrapped this in a groovy script to walk the file tree and run it against all pom.xml files. This is the final script I came up with. It walks the tree for pom.xml files. For each file it finds any groups of com.chrisdail.project and replaces the version number with my new version number of 2.0.


import javax.xml.transform.TransformerFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource

def xslt = '''
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:m="http://maven.apache.org/POM/4.0.0" exclude-result-prefixes="m">
    <xsl:template match="m:version[../m:groupId='com.chrisdail.project']">
		<version>2.0-SNAPSHOT</version>
    </xsl:template>
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
'''.trim()

def processFile = {
    def file = new File(it, "pom.xml");
    if (file.isFile()) {
        println "Processing: $file"

        def writer = new StringWriter()
        def factory = TransformerFactory.newInstance()
        def transformer = factory.newTransformer(new StreamSource(new StringReader(xslt)))
        transformer.transform(new StreamSource(new FileReader(file)), new StreamResult(writer))

        file.write(writer.toString())
    }
}

file = new File("/path/to/root/dir")
processFile(file)
file.eachDirRecurse(processFile)

It did take a bit more time than changing all of the pom.xml files manually but it was much more satisfying.

Building with Maven

I’ve decided to use Apache Maven for building the code for my new project. So far I have had a love-hate relationship with Maven. If you don’t know what maven is, the folks over at Apache say Maven is …

“… a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.”

Unfortunately that definition is about as vague as you can get so I will explain what Maven gives me and my project. This also happens to be the list of what I love about Maven:

  • Maven enforces a standardized project structure to all modules in a project.
  • Maven handles dependencies between libraries.
  • Maven builds all of my code and creates a distribution package.

Essentially by using Maven, I can get all of these things without having to write and maintain ant scripts to do most of the work for me. Maven is not without its problems though.

  • Often times the number of lines of XML you need to write ends up to be just as complicated and long as an ant script to do the same thing.
  • I’ve found a lot of bugs particularly with the assembly module. It seems to include dependencies of modules that are set with the “compile” or “test” scope only.
  • The Groovy building plugin for maven does not yet work for Groovy 1.5.x.

I still think using maven was a good choice for my project. It may have some qwerks but I think that I am further ahead than if I had to build everything from scratch.

Using Maven to Generate a Build Number

Earlier I metioned that I use the subversion revision number as a build number. This is actually quite easy to do from Maven. The following plugin descriptor provides you access to the subversion revision number using the ${scm.revision} property.


  <build>
    <plugins>
      <plugin>
        <artifactId>maven-scm-plugin</artifactId>
        <executions>
          <execution>
            <id>getting-scm.revision</id>
            <phase>validate</phase>
            <goals>
              <goal>update</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Once you have access to the revision number, you can construct a build number using the product version and the revision number. I have added this build number to the Implementation-Version property of the jar manifest. The following plugin definition does this for me:


      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <archive>
            <manifestEntries>
              <Implementation-Version>${this.version}.${scm.revision}</Implementation-Version>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>

The resulting manifest in the jar looks something like this:


Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: cdail
Build-Jdk: 1.6.0_03
Implementation-Version: 1.0-SNAPSHOT.93

From Java code, this build number can be easily retrieved. The following code retrieves the Implementation-Version from the manifest:


Package p = getClass().getPackage();
String version = p.getImplementationVersion();

The result is quite elegant but it takes a bit of work to get things into place. Like with many other things to do with Maven, it takes a while to figure out how to do what you want and you need to write a bunch of XML. Once that was done, everything fell into place. It is hard to say at this point if this is better or worse than the chunk of ant script I used to use to perform the same function.