Writing Your pom Files in Groovy - a Sneek Preview of Maven 3's Polyglot Features
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
John is a freelance consultant specialising in Enterprise Java, Web Development, and Open Source technologies, currently based in Wellington, New Zealand. Well known in the Java community for his many published articles, John helps organisations to optimize their Java development processes and infrastructures and provides training and mentoring in open source technologies, SDLC tools, and agile development processes. John is principal consultant at 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 57 posts at DZone. You can read more from them at their website.
- Login or register to post comments
- 1902 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)










Comments
Thomas 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
lptr 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')MykolaGolubyev replied on Thu, 2009/10/22 - 8:11am
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.
StormTAG 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.