John is an experienced consultant specialising in Enterprise Java, Web Development, and Open Source technologies, currently based in Sydney, Australia. Well known in the Java community for his many published articles, and as author of Java Power Tools and Jenkins: The Definitive Guide, and founder of the open source Thucydides Automated Acceptance Test Library project, John helps organisations to optimize their Java development processes and infrastructures and provides training and mentoring in agile development, automated testing practices, continuous integration and delivery, and open source technologies in general. John is the CEO of Wakaleo Consulting, and runs several Training Courses on open source Java development tools and best practices. John is a DZone MVB and is not an employee of DZone and has posted 125 posts at DZone. You can read more from them at their website. View Full User Profile

Writing Your pom Files in Groovy - a Sneek Preview of Maven 3's Polyglot Features

10.22.2009
| 5535 views |
  • submit to reddit

Maven 3 is promising to be the most significant upgrade since the release of Maven 2. While maintaining backward compatibility with existing Maven 2 projects, it introduces a number of powerful and compelling new features, such as a complete rewrite of the internal architecture, OSGi support and multi-language pom files. In this article, I will be giving a preview of this last feature.

One exciting new feature in Maven 3 is it's ability to work with pom files written in non-XML notations. The Maven core now provides an underlying DSL to access the Maven internals, and write POM files in the language of your choice. This currently includes scripting languages like Groovy, Ruby, and others. In short, you will be able to write a DSL for virtually any scripting language you like that can hook into the Maven internals and pilot the Maven build process.

This article focuses on the Groovy support - writing your POM files in Groovy.

With Maven 3, you can use a Groovy DSL that maps directly to the XML pom format. So, instead of:

  <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>

you could write:

dependencies {
dependency { groupId 'junit'; artifactId 'junit'; version '4.7'; scope 'test' }
}

 

Let's take a closer look. A handy way to start is to use the translator tool, which lets you translate an existing pom.xml file into:

$ translator pom.xml pom.groovy

 

This generates a Groovy transcription of your pom file, which looks and feels just like a traditional pom file, except in Groovy. Here is a simple one:


project {
modelVersion '4.0.0'
parent {
artifactId 'babble'
groupId 'com.sonatype.training'
version '1.0.6-SNAPSHOT'
}
artifactId 'babble-core'
version '1.0.6-SNAPSHOT'
name 'babble-core'
url 'http://maven.apache.org'
build {
testResources {
testResource {
filtering 'true'
directory 'src/test/resources'
}
}
}
dependencies {
dependency {
groupId 'junit'
artifactId 'junit'
version '4.7'
scope 'test'
}
}
profiles {
profile {
id 'development'
properties {
'log4j.level' 'DEBUG'
}
}
profile {
id 'production'
properties {
'log4j.level' 'WARN'
}
}
}
properties {
'log4j.level' 'info'
}
}

If you're familiar with the XML pom files, this will read pretty easily - it's essentially an XML pom file without the noise generated by the XML tags. Although it's an obvious improvement, some of the transcribed Groovy DSL code might still seem a bit wordy to some. For example, a set of project dependencies might look like this:
   
dependencies {
dependency {
groupId 'junit'
artifactId 'junit'
version '4.7'
scope 'test'
}
dependency {
groupId 'org.hamcrest'
artifactId 'hamcrest-all'
version '1.1'
}
dependency {
groupId 'log4j'
artifactId 'log4j'
version '1.2.12'
}
}

However, you can make this more concise simply by using semi-colons to separate the dependency elements:

   
dependencies {
dependency { groupId 'junit'; artifactId 'junit'; version '4.7'; scope 'test' }
dependency { groupId 'org.hamcrest'; artifactId 'hamcrest-all'; version '1.1' }
dependency { groupId 'log4j'; artifactId 'log4j'; version '1.2.12' }
}

This is certainly more concise and more readable, and goes with the general tendancy of moving away from XML as a build scripting language in favour of more lightweight notations. But the real power of this is that it is effectively an interface to the Maven 3 core, that gives you full access to all of the Maven features. The Maven 3 core is rock solid, and you can leverage all the existing features and plugins from the Maven 2 ecosphere.

Maven 3 is supposed to be fully backward-compatible with your existing Maven 2 projects, with the exception, I believe, of a few fairly rare corner cases. I tested Maven 3 against a few large real-world projects (including a couple of gnarly ones), and indeed everything seemed to work just fine. I've also converted the pom.xml files into Groovy equivalents and run the builds successfully. Performance is good - I didn't notice any real difference between using an XML pom file and a Groovy one.

I've just scratched the surface of Maven 3 Groovy support, but hopefully this will give you some idea of what it's all about. In the coming weeks, I'll write about some of the other new features in Maven 3.

From http://weblogs.java.net/blog/johnsmart

Published at DZone with permission of John Ferguson Smart, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Thomas Mueller replied on Thu, 2009/10/22 - 2:44am

dependencies {
    dependency { groupId 'junit'; artifactId 'junit'; version '4.7'; scope 'test' }
}
What about:
<dependencies>
    <dependency groupId="junit" artifactId="junit" version="4.7" scope="test" />
</dependencies>

Donny A. Wijaya replied on Thu, 2009/10/22 - 2:50am

Hi John,

The Groovy support is very cool!!

I think it would be cooler if we can group the dependencies under the scope instead of adding the scope on each of them.

dependencies {

    test {

        dependency { groupId 'junit'; artifactId 'junit'; version '4.7' }; 

        dependency { groupId 'org.springframework'; artifactId 'spring-test'; version '2.5' };

    }

}

And last question: is it possible to divide pom into smaller pieces like Ant build.xml?

ff aaa replied on Thu, 2009/10/22 - 3:16am

Agree with Thomas. Problem is the POM xml definition here. They messed it up with a extremely verbose format. Groovy syntax may be better, but it is another dependency and more things to learn..

Lóránt Pintér replied on Thu, 2009/10/22 - 3:38am

I'm not sure I like this. Maven, as it is now, unifies the build across projects. Across a lot of projects. This has numerous advantages, one of which is that developers can easily move between Maven-built projects. By enabling Groovy, Ruby, and god knows what other syntaxes, this system is broken, and the benefit of easy movement is gone.

I expect that this is not just about the format, though, but also about the ability to use the scripting environment to customize the build. I'm not sure I like that either. Again, Maven's strenght (at least compared to Ant) is in how simple the build configuration is: once you've learnt he how Maven works, you can read through a few files in a new project, and you know what is going to happen. Once scripting is enabled (and the same goes for include files), we are back at an Ant-like chaos.

This is not to say that I don't hate the verbosity of Maven's XML sometimes, or that I don't think that scripting would come in handy once in a while. However, instead of providing several flavors of non-XML, I would like to see only one. And if the Maven developers think that there is need for more customizable builds, probably they should make the creation of plugins easier, but they should not let the current clear system be smudged by scripting.

Just my ¢2.

Jens Riboe replied on Thu, 2009/10/22 - 7:04am

This is indeed cool.

Regarding the suggestion about grouping based on scope, I would like to generalize it to nested grouping based on any of the attributes. This would be similar in style to how properties and config in general works in groovy.

dependencies {
  groupId('org.whatever') {
    version('1.17') { 
      scope('compile') {
        artifactId('Xyz')
      } 
      scope('test') {
        artifactId('AbcTester')
      }
    }
  }
}

 

Mykola Golubyev replied on Thu, 2009/10/22 - 8:11am

This sounds like a joke. Really. Groovy is nice, but I am not sure you can validate groovy code by using xsd. And some IDEs already can complete xml by looking at xsd which is good. Are there any groovy-builders-code-complete tools?

matt inger replied on Thu, 2009/10/22 - 9:06am

Are we ever going to get the ability to load a properties file?  The biggest thing holding me back from using maven is the kludgy multi-module support.  Having to have the project version in child pom file is a hack.  It means every time you branch and create a new version, you have to change all your pom files.  I realize that can be scripted, but it's still a revision in your source repository for no good reason.

With ant, i can just create a master build.properties file for the entire project, and define the version in there, and just include the properties file in all the child modules.  Let maven resolve out all and remove the property file inclusions and do the property replacements before it delivers the pom files to the cache or the repository.  I'd love to be able to do this in maven:

 

<project>

   <propertyfile file="pom.properties" />

   <version>${my.version}</version>

</project>


and then in the child pom:

 

<project>

   <propertyfile file="../pom.properties" />

   <parent>

      ...

      <version>${my.version}</version>

   </parent>

</project>

 

 

That way, when you actually branch a project, you change 1 file (pom.properties) to update the version.  It makes more sense in terms of your source repository, in that your version # lives in 1 place, and all your dependent projects retrieve it from a single spot.

 

Andrew Arrigoni replied on Thu, 2009/10/22 - 10:11am

@Matt Inger How is that much different than changing the versions in the properties section of your parent pom?

 

I, for one, definitely like this idea but I do have a lot of the same reservations as lptr. I'm just beginning to really play with Maven outside of "Make War file archetype, fill War file archetype" but I did always appreciate that there was a "Maveny" way of doing things. So long as that is kept throughout, I welcome the lessening verbosity.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.