More Groovy Magic with Maven pom Files
Join the DZone community and get the full member experience.
Join For FreeLast time, I introduced some of the new Groovy support available in Maven 3, and looked at how you will be able to write your pom files in Groovy, or in other non-XML notations. In this article, we'll take a further look at what you can do with a Maven pom file written in Groovy.
Jason Dillon, the guy who brought us GMaven, has been working hard on extending the Groovy pom scripting features, and is coming up with some great new capabilities. In the last article, we saw how the Groovy DSL makes dependencies more concise, with dependency declarations along the following lines:
dependencies {
dependency { groupId 'junit'; artifactId 'junit'; version '4.7'; scope 'test' }
}
In fact, you can do even better than this. A short-hand notation for dependencies lets you define dependencies in a single line. So
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency
becomes:
dependency('junit:junit:4.5:test')
This also works for the project parent, plugins, modules and many other elements. For example, you could write the following:
project {
parent('tweeter:co.nz.codingdojo.tweeter:1.0.0-SNAPSHOT')
...
}
This shorthand notation also works with dependency exclusions. Here is a real-world example from the graven project itself:
dependencies {
dependency('org.codehaus.groovy:groovy:1.7-beta-2') {
exclusions('junit:junit', 'org.apache.ant:ant', 'org.apache.ant:ant-launcher')
}
}
Here is a more complete example, showing this notation in action in the parent element, as well as in dependencies and plugins:
project(modelVersion: '4.0.0') {You can also bind Groovy scriptlets to different phases in the lifecycle with a minimum of fuss. For example, you will be able to integrate Groovy code directly at different points in the lifecycle. At this stage, the syntax uses the $execute macro, and looks something like this:
parent('tweeter:co.nz.codingdojo.tweeter:1.0.0-SNAPSHOT')
artifactId 'tweeter-web'
packaging 'war'
name 'Tweeter Web Application'
dependencies {
dependency('javax.servlet:jstl:1.2')
dependency('junit:junit:4.7:test')
}
build {
plugins {
plugin('org.mortbay.jetty:maven-jetty-plugin:6.1.21') {
configuration {
port '9090'
scanIntervalSeconds '5'
stopPort '9966'
stopKey 'foo'
}
executions {
execution(id: 'start-jetty', phase: 'pre-integration-test') {
goals('run')
configuration {
scanIntervalSeconds '0'
daemon 'true'
}
}
}
}
}
}
}
project {Within the Groovy closure, you will be able to access the usual pom variable such as $project and $settings, as you can with GMaven.
build {
$execute(id: 'test1', phase: 'validate') {
println "foo"
}
$execute(id: 'test2', phase: 'compile') {
println "bar"
}
...
}
You can also use Groovy in the pom file itself, to make the pom file itself more dynamic and concise. For example, in this example (taken from the graven pom file), the project modules are defined in a central list, and used both in the dependency management section (to avoid duplicating the version number for each module) and in the modules element:
project {This really is the best of both worlds. If you need flexibility, you can add Groovy scripting to do most anything you want. However it remains within the structure of the Maven build lifecycle. We are not going back to Ant-like anarchy of build scripts built up of arbitrary targets and task dependencies: 'mvn verify', for example, will still do what you expect it to do.
...
def mods = ['pmaven-common','pmaven-cli','pmaven-maven-plugin',
'pmaven-groovy','pmaven-yaml','pmaven-jruby']
...
dependencyManagement {
dependencies {
mods.each { artifact ->
dependency {
groupId 'org.sonatype.pmaven'
artifactId "$artifact"
version '1.0-SNAPSHOT'
}
}
}
...
modules(*mods)
}
Some readers seemed concerned that this would just add another notation to learn, and rightly so! Keeping your code maintainable is an essential part of good development practices! However, this is not a totally new formalism - this is more a transcription of the XML pom format with a few fairly intuitive short-cuts. For anyone familiar with Groovy and Maven, a pom file written in Groovy is very easy to read and understand indeed.
Indeed, under the hood, the pom files are converted to the canonical XML pom format that we all know and love. When an artifact is deployed to a Maven repository (be it a local one, or the official central repository), the Pom file will be in the standard, canonical XML format. The support for multi-language pom files is clearly intended to make your live easier within your organization writing and maintaining pom files in a format that suits you - not to turn the central repository into a Tower of Babel.
Regarding tool support, the standard m2eclipse integration will work fine with any POM file format, as m2eclipse uses the canonical XML format under the hood. However, Groovy support in Eclipse being what it is, the pom editor will probably take a while before you get all of the nice auto-completion features you currently get with the XML format. Nevertheless, for a groovy-savvy developer, this new pom format is a great step forward.
Opinions expressed by DZone contributors are their own.
Comments