A Groovy-based backend, primarily intended for building Java-based
software, was introduced in abuild version 1.1. This framework
replaces the older, now deprecated, xml-based ant framework that
was present in abuild version 1.0.
[36]
The old ant framework was extremely limited in capability in
comparison to abuild's make backend, and it was always
considered tentative. Abuild's groovy backend is at least as
powerful as its make backend offers comparable functionality
across the board. As of abuild 1.1, the specific rules provided
for building Java code lack the maturity of the C/C++ rules
provided as part of abuild's make backend, but they still
represent a significant improvement over what was available in
abuild 1.0.

You might wonder why you should consider using abuild's Groovy
backend when other Groovy/ant-based build systems, such as Gant and Gradle are available. You may
wonder why you should use abuild for Java at all when you could
get transitive dependency management with Ivy or Maven. Surely those tools
may be the right tools in some environments, particularly for
Java-only projects, but, at least at their current stage of
development, they lack the same cross-platform/cross-language
interoperability support offered by abuild, even as they offer
more mature rules for building Java code and better integration
with other “standard” Java build environments. But
this is the abuild manual, not a comparison of various Java
build options, so, without further delay, we'll continue with our
description of abuild's Groovy backend.

19.1. A Crash Course in Groovy

Although you don't really have to understand Groovy to use the
above-described features of the Groovy backend, if you want to
get the most out of abuild's Groovy backend, it helps to have a
decent understanding of the Groovy language, and you
will certainly need to understand at least some basic Groovy to
take advantage of more advanced customization or to write your
own rules. If you are already comfortable with Groovy, feel free
to skip this section.

Providing a tutorial on Groovy would be out of scope for this
manual. However, there are a few Groovy idioms that abuild (as
well as many other Groovy-based systems) make heavy use of, and
understanding at least that much, particularly if you are already
a Java programmer, will certainly help you to make sense of what
is going on here.

Closures

A closure is an anonymous block of code
that is treated as an object. When a closure is run,
variables and functions that it uses are generally resolved in
the context in which the closure was
defined rather than in the context in
which it is run. You can't get very far in Groovy without
having a basic understanding of closures. You don't have to
understand closures to use abuild's
Groovy backend, but you certainly have to understand them, at
least at some level, when you get to the point of writing
custom rules.

Although a closure is often written as a literal block of code
enclosed in curly braces, Groovy allows you to treat any
function as a closure. In particular, Groovy allows you take
a particular method call of a specific
instance of an object and treat that method call as
a closure. This feature is sometimes known as
bound methods and is present in many
modern programming languages. The syntax for creating a
closure from a method in Groovy is
object.&methodName. Abuild's Groovy
backend uses this construct heavily in its rule code.

Automatic Bean Formation

In Groovy, calling object.field is just
“syntactic sugar” for
object.getField(). In other words, if an
object has a method called getField, then
accessing object.field is exactly the same
as calling object.getField(). It is
important to understand this when looking at Groovy code that
is interfacing with the Java standard library. For example,
object.class.name is the same as
object.getClass().getName(), which may not
be obvious to a Java programmer with no prior Groovy
experience.

List and Map Literals

Groovy supports lists and maps that are similar to those in
Java. However, Groovy has a syntax for list and map
literals that can appear directly in
code. We make heavy use of these in the abuild Groovy
backend, and in fact, you will find heavy use of these in just
about any Groovy code.

The syntax for a list literal is [val1, val2, val3,
...]. The syntax for a map literal is
['key1': value1, 'key2': value2, ...].

The << Operator

Groovy overloads the left-shift operator
(<<) for appending to lists. For
example, this code:

def var = []
var << 1
var << 2

would result in a list whose value is [1,
2]. The << operator, like
all operators in Groovy, is just a shortcut for calling a
specific corresponding method. This method returns the object
being appended. So the above code could also have been
written as

def var = []
var << 1 << 2

We use this syntax sometimes to append maps to lists of maps
as it's a little cleaner (in the author's opinion) than
explicitly coding lists of maps.

Named Parameters

Under the covers, Groovy runs on top of the Java virtual
machine. As such, Groovy function calls are really just like
Java function calls: a function may take a specific number of
arguments that appear in a specific order. The Java language
doesn't support named parameters, so there is no encoding of
them in Java byte code. Yet Groovy appears to support named
parameters, so how does this work?

With Groovy, you often see function calls that look like they
have named parameters. For example, the following would be a
valid function call in Groovy:

f('param1': value1, other, 'param2': value2)

You can even mix what look like named parameters with regular
parameters as in the above example. What Groovy does when it
sees named parameters is that it gathers them all up in a
single map and then passes that map to the function as the
first argument. As such, the above call is exactly
equivalent to the following:

f(['param1': value1, 'param2': value2], other)

Trailing Closures

In Groovy, it is common to see something that looks like a
function call, or even bare function name, followed by a block
of code in curly braces. In fact, this construct is used in
virtually every Abuild.groovy file. This
points to another special bit of Groovy syntax surrounding
function calls. Specifically, if a function call is
immediately followed by one or more closures, those closures
are passed to the function at the end of its parameter list.
Additionally, if a function is being called with no arguments
prior to the trailing closure, the parentheses can be
omitted. So the following blocks of code are
exactly equivalent:

f({println 'hello'})
f() {
println 'hello'
}
f {
println 'hello'
}

In all three cases, the function f is
being called with a single argument, and that argument is a
closure that, when run, prints the string
hello followed by a newline.

Closure-based Iteration

Iteration over lists and maps is so common that Groovy
provides convenience methods for calling a closure on each
element of a list or map. In Groovy, a closure with one
parameter can access the single parameter anonymously with
through the variable it. If there are
multiple parameters (or zero parameters), they have to be
named and followed by -> to separate
them from the body of the closure.

If you have a list in a variable called
items, the following code:

items.each { f(it) }

would call the function f for each
argument of the list. If have a map in a variable called
table, this code:

table.each { k, v -> f(k, v) }

would call the function f on each key and
value in the map. All that's happening here is that Groovy is
calling the each method of the list and
map objects with a closure passed to it as the last argument,
which should hopefully be clear now that you've seen the
trailing closure feature.

Safe Dereference

How often have you found yourself writing code where you first
check whether a variable is null and, only if it isn't null,
access it? Groovy offers a shortcut for this. This code:

obj?.method()

is the same as

if (obj != null)
{
obj.method()
}

but it's a lot easier to write!

These features are often combined. In fact, this is extremely
common when using Groovy's AntBuilder,
which abuild uses very heavily. So if you see something like
this:

There's a lot more to Groovy than in this tiny crash course. You
are encouraged to seek out Groovy documentation or get a good
book on the language. But hopefully this should be enough to get
you through the examples in this documentation.