About the Author

Phillip Verheyden

Software Architect


Broadleaf with Groovy and Gradle - Part 1

Would you rather skip the post and go straight to the code? Go check it out on GitHub!

I got a little bored one weekend and wanted to try my hand at some of the new (at least in terms of Maven) technologies Spring has been pushing: Groovy and Gradle. Spring moved all of their build scripts to Gradle a couple of years back and they have been leading the charge on the Grails framework adoption (one of the main consumers of Groovy code).

Some goals that I had for the project:


  • Automated builds on Jenkins
  • Deploy SNAPSHOTS and GAs to our internal Maven repositories
  • Provide 1-1 feature matching for Maven POMs that are used in our other modules
  • Compare and contrast Gradle features to Maven


  • Write something very self-contained (needed to finish it in a few days)
  • Operate alongside of our normal Java code in the rest of the Broadleaf framework
  • See how good the IDE support is (I use Eclipse)
  • Try to be as idiomatic as possible - make sure my code conformed to The Groovy Way™ as much as possible

The Holy Gradle

For this first post I will be detailing my first experience with Gradle, starting with matching up the features that we use in our existing Maven builds.

Automatically apply license headers when building

For Maven, the configuration looks like this for our open source modules:

                    <organizationName>Broadleaf Commerce</organizationName>

Wow. That is a LOT of XML. What about with Gradle?

// From GitHub: https://github.com/hierynomus/license-gradle-plugin

apply plugin: 'license'

license {
    ext.startYear = 2014
    ext.endYear = Calendar.getInstance().get(Calendar.YEAR);
    ext.company = 'Broadleaf Commerce'
    ext.description = project.description
// Automatically apply the license when building the Jar

jar.dependsOn licenseFormat

Definite win for Gradle!

Deploying to our Sonatype Nexus

This was actually pretty tricky. I went through 3-4 different plugins before I found the one I was happy with that left me with the simplest configuration. I originally attempted to use the old upload artifacts configuration which I couldn't get working how I wanted it. I then went to the Maven publisher plugin which is going to be standardized in later versions of Gradle (currently in the incubation phase). While this is a definite improvement over the previous upload artifacts, I still had trouble differentiating between a release and a SNAPSHOT repository and everything I did to try to make it work felt like a hack.

With a little Google-fu I came across a Sonatype nexus plugin which suited my needs perfectly and provided configuration that I was used to with Maven poms:

// From GitHub: https://github.com/bmuschko/gradle-nexus-plugin

apply plugin: 'nexus'

nexus {
    attachJavadoc = true
    attachSources = true
    attachTests = true
    repositoryUrl 'http://nexus.broadleafcommerce.org/nexus/content/repositories/releases'

    snapshotRepositoryUrl 'http://nexus.broadleafcommerce.org/nexus/content/repositories/snapshots'


Not a huge advantage over Maven and I was disappointed in the OOB Gradle support for deploying to Maven repositories.

Optional dependencies

We use this at Broadleaf so that the Broadleaf framework dependency declared in one of our add-on modules does not inadvertently get transitively included and conflict with the version of Broadleaf that you are targeting in your own site. This allows a module to be compiled against, say, Broadleaf 3.1.0-GA but your custom project target 3.1.2-GA.

Unfortunately Gradle doesn't have OOB support for the optional keyword. Lucky for us a bit more Google-fu magic led me to the propdeps plugin. This allowed my optional dependencies to look like this:

apply plugin: 'propdeps'
apply plugin: 'propdeps-maven'
dependencies {
    optional 'org.broadleafcommerce:broadleaf-common:3.1.0-GA'
    // other compiletime/runtime dependencies


The other way to do this is to modify the generated pom.xml and manually modify the dependency to mark it as 'optional'. This is a much cleaner configuration and gives the exact same result

JRebel support

Jrebel created their own Gradle plugin that works great! The configuration is also super simple, especially the ability to use profiles (don't want to include rebel.xml in the final release jar)

apply plugin: 'rebel'
// Simulates a Maven profile. Activate in the same way, 'gradle build -Pblc-development'

if (hasProperty('blc-development')) {
    jar.dependsOn generateRebel

Looks pretty good for matching up to Maven features. In most of these cases, the configuration is much easier to read.

But the real killer feature for me with Gradle is that the entire build file is just a Groovy script. I did not realize just how AWESOME that would be until I started using it. What's that, you're not sure what a value of some build variable is when you run your build? No problem! Just throw in a println "Var1 is: " + var1 and check the output.

Haven't convinced you yet? Check out this other little snipped I cooked up to collect properties given to the Gradle build script and pass them to the test execution:

test {
    // Collect all of the broadleaf.rackspace properties and pass them in as system arguments to the test execution.

    // This little snippet converts all the key-value pairs into -D args and then subtracts the empty strings

    jvmArgs = project.properties.collect {k,v -> k.startsWith('broadleaf.rackspace') ? "-D$k=$v" : ''}.minus('')

As my good friends OutKast would say, so fresh and so clean, clean.

Closing Thoughts

Overall I would say that the Gradle build script came out much more readable and cleaner than a Maven pom.xml. I was a little disappointed in Gradle missing some Maven features out of the box, but the learning curve to write custom Gradle modules is so low and the ecosystem is so good that it wasn't that big of a deal. And again, the fact that the build script is just a Groovy script is a huge plus.

Check out part 2 where I talk about IDE support and review the Groovy code for the module itself!