Skip to content

Wakaleo Consulting

  Home Blog More Groovy Magic with Maven pom files
More Groovy Magic with Maven pom files PDF Print E-mail
Friday, 30 October 2009 08:19

Last 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') {
    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'
                        }
                    }
                }
            }
        }
    }
}

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:

project {
   build {
       $execute(id: 'test1', phase: 'validate') {
           println "foo"
       }

       $execute(id: 'test2', phase: 'compile') {
           println "bar"
       }
       ...
}
Within the Groovy closure, you will be able to access the usual pom variable such as $project and $settings, as you can with GMaven.

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 {
    ...
    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)
}

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.

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.

Tags See All Tags Add New Tag...

Please Enter New Tags Separated By Comma's
  Or Close

Groovy  Maven 

Trackback(0)
Comments (5)Add Comment
0
...
written by Donny, October 30, 2009
the definition for dependency is much better than the old one!!! great job!!
0
Consultant
written by Viraf Karai, October 31, 2009
It's nice to see Groovy coming of age. I'm a huge lover of Java, Groovy and Maven 2. I can't wait for Maven 3 to come out. The POMs appear more readable and have a higher signal-to-noise ratio with the Groovy DSL. I do like XML but there are times it gets way too verbose especially when elements are used instead of attributes. The VmWare folks appear to be headed in a similar direction - convention over configuration in their Spring 3.0 release with heavy use of Java annotations.

Maven is truly excellent and makes large projects so much more manageable and standard. Making Maven even more usable is a great objective.
0
...
written by Sakuraba, November 02, 2009
I was one of the critics of the new syntax, but I must say that being able to execute something more easily at every stage of the build process is a plus. But hasnt this been possbiel with the AntRunner Plugin, too?

Is there some kind of implicit "Context"-object accessible from inside those execute statements? That way one could read some build profile values or anything like that.
0
...
written by Jason Dillon, November 02, 2009
There is some context, its still a bit alpha, but I imagine the end result will be very similar to the context available to scripts run with the GMaven's execute goal.
0
Groovy/Maven iz off the wallz!
written by Cliff, November 07, 2009
I've been out of the Groovy/Maven loop for quite some time and each time I look up you guys are doing something else awesome! Somebody (me?) needs to develop Groovy/Maven support for XCode and the iPhone SDK. Even better, someone (Jetbrains?) need to develop ObjC support in IntelliJ. That along with build time Mac/iPhone SDK support via Maven would bring me back to the days of yesteryear... when I use to babble about Groovy DSLs and dependency injection and all.

Write comment

security code
Write the displayed characters


busy