Skip Navigation

Groovy Maven

Chapter 2

2.1 Introduction

Groovy is just that: Groovy, and maybe in future versions of this book, I'll go on and on and on about how wonderful it is. For now, the pre-alpha Maven Cookbook gets straight to the content. This chapter contains a number of recipes that should make it easier for you to integrate Groovy into your Maven builds. For more information about Groovy, take a look at the Groovy project page https://groovy-lang.org/.

2.2. Running an Inline Groovy Script in a Maven Build

While Maven covers a lot of ground, there are certainly times when you just want to shell out to a script to get something simple done without having to write a custom plugin. Groovy is ideal for these situations because it provides you with a simple, dynamic scripting language that can be added directly to a project's POM.

2.2.1. Task

You need to run some Groovy script as a part of your build process.

2.2.2. Action

Put some Groovy in your project's POM like this:

Example 2.1. Running a Groovy Script from a POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mcookbook</groupId>
<artifactId>groovy-script</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>groovy-script</name>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<id>groovy-magic</id>
<phase>prepare-package</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def depFile = new File(project.build.outputDirectory, 'deps.txt')
project.dependencies.each() {
depFile.write("${it.groupId}:${it.artifactId}:${it.version}")
}
ant.copy(todir: project.build.outputDirectory ) {
fileset(dir: project.build.sourceDirectory)
}
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Example 2.1, “Running a Groovy Script from a POM” configures the GMaven Plugin's execute goal to execute during the prepare-package phase. The source configuration supplies a Groovy script which is run during the execution of the execute goal. Also note that the execution has an id element with a value of groovy-magic. This id element isn't required if you are only configuring one execution for a plugin, but it is necessary once you define more than one execution for a given plugin.

The Groovy script included, creates a file named "deps.txt" in ${basedir}/target/classes, it then iterates through the project's declared dependencies, and then it copies all of the source in ${basedir}/src/main/java into the ${basedir}/target/classes directory. This script demonstrates the use of Groovy's closure syntax and ease with which you can manipulate the filesystem. Groovy is an ideal scripting language for manipulating text and working with files. To test this script example, run mvn package as shown below.

~/examples/groovy/groovy-script$ mvn package -Dmaven.test.skip=true
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building groovy-script
[INFO] task-segment: [package]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[WARNING] Using platform encoding (MacRoman actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory ~/examples/groovy/groovy-script/src/main/resources
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[WARNING] Using platform encoding (MacRoman actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory ~/examples/groovy/groovy-script/src/test/resources
[INFO] [compiler:testCompile]
[INFO] Not compiling test sources
[INFO] [surefire:test]
[INFO] Tests are skipped.
[INFO] [groovy:execute {execution: default}]
[INFO] [jar:jar]
[INFO] Building jar: ~/examples/groovy/groovy-script/target/groovy-script-1.0-SNAPSHOT.jar

After running this example, list the contents of ${basedir}/target/classes/deps.txt, and you should see the following contents:

~/examples/groovy/groovy-script $ more deps.txt
org.apache.maven:maven-model:2.2.0
2.2.3. Detail

This simple Groovy script contained a number of references to implicit objects such as project and ant, it also demonstrated the simple syntax of Groovy and its closure-friendly nature of Groovy.

2.3. Executing Groovy Scripts in a Maven Build

2.3.1. Task

You need to execute one or more groovy scripts in a Maven build.

2.3.2. Action

Configure the execute goal of the GMaven plugin, reference the Groovy script in the source configuration for the execution. The example POM shown in Example 2.2, “Executing External Groovy Scripts in a Maven Build” configures two executions of the execute goal referencing two scripts stored in ${basedir}/src/main/groovy.

Example 2.2. Executing External Groovy Scripts in a Maven Build

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mcookbook</groupId>
<artifactId>groovy-script-ex</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>groovy-script-ex</name>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<id>create-deps-file</id>
<phase>process-classes</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>${basedir}/src/main/groovy/CreateDeps.groovy</source>
</configuration>
</execution>
<execution>
<id>copy-the-source</id>
<phase>prepare-package</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>${basedir}/src/main/groovy/CopySource.groovy</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

The CreateDeps.groovy script creates a file named deps.txt in ${basedir}/target/classes which contains a list of direct project dependencies, and the CopySource.groovy script copies the source from ${basedir}/src/main/java to ${basedir}/target/classes.

Example 2.3. The CreateDeps.groovy Script

def depFile = new File(project.build.outputDirectory, 'deps.txt')
project.dependencies.each() { depFile.write("${it.groupId}:${it.artifactId}:${it.version}") }

Example 2.4. The CopySource.groovy Script

ant.copy(todir: project.build.outputDirectory ) {
fileset(dir: project.build.sourceDirectory)
}

2.4. Writing Plugins in Groovy

Groovy is a dynamic language based on the Java Virtual Machine which compiles to Java bytecode. Groovy is a project in the Codehaus community. If you are fluent in Java, Groovy will seem like a natural choice for a scripting language. Groovy takes the features of Java, pares down the syntax a bit, and adds features like closures, duck-typing, and regular expressions. For more information about Groovy, please see the Groovy web site at https://groovy-lang.org/.

https://groovy-lang.org/

To create a Maven Plugin using Groovy, you only need two files: a pom.xml and a single Mojo implemented in Groovy. To get started, create a project directory named firstgroovy-maven-plugin. Place the following pom.xml in this directory.

Example 2.5. POM for a Groovy Maven Plugin

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook.plugins</groupId>
<artifactId>firstgroovy-maven-plugin</artifactId>
<name>Example Groovy Mojo - firstgroovy-maven-plugin</name>
<packaging>maven-plugin</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.codehaus.mojo.groovy</groupId>
<artifactId>groovy-mojo-support</artifactId>
<version>1.0-beta-3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo.groovy</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

What's going on in this POM? First, notice that the packaging of the POM is maven-plugin because we are creating a project that will package a Maven plugin. Next, note that the project depends on the groovy-mojo-support artifact in the org.codehaus.mojo.groovy group.

Then under src/main/groovy in a directory org/sonatype/mavenbook/plugins, create a file named EchoMojo.groovy which contains the EchoMojo class.

Example 2.6.

package org.sonatype.mavenbook.plugins

import org.codehaus.mojo.groovy.GroovyMojo

/**
* Example goal which echos a message
*
* @goal echo
*/
class EchoMojo extends GroovyMojo {

/**
* Message to print
*
* @parameter expression="${echo.message}"
* default-value="Hello Maven World"
*/
String message

void execute() {
log.info( message )
}
}