Introduction

Groovy…​

  • is an agile and dynamic language for the Java Virtual Machine

  • builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk

  • makes modern programming features available to Java developers with almost-zero learning curve

  • provides the ability to statically type check and statically compile your code for robustness and performance

  • supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain

  • makes writing shell and build scripts easy with its powerful processing primitives, OO abilities and an Ant DSL

  • increases developer productivity by reducing scaffolding code when developing web, GUI, database or console applications

  • simplifies testing by supporting unit testing and mocking out-of-the-box

  • seamlessly integrates with all existing Java classes and libraries

  • compiles straight to Java bytecode so you can use it anywhere you can use Java

1. Groovy Language Specification

1.1. Syntax

This chapter covers the syntax of the Groovy programming language. The grammar of the language derives from the Java grammar, but enhances it with specific constructs for Groovy, and allows certain simplifications.

1.1.1. Comments

Single line comment

Single line comments start with // and can be found at any position in the line. The characters following //, till the end of the line, are considered part of the comment.

// a standalone single line comment
println "hello" // a comment till the end of the line
Multiline comment

A multiline comment starts with /* and can be found at any position in the line. The characters following /* will be considered part of the comment, including new line characters, up to the first */ closing the comment. Multiline comments can thus be put at the end of a statement, or even inside a statement.

/* a standalone multiline comment
   spanning two lines */
println "hello" /* a multiline comment starting
                   at the end of a statement */
println 1 /* one */ + 2 /* two */
GroovyDoc comment

Similarly to multiline comments, GroovyDoc comments are multiline, but start with /** and end with */. Lines following the first GroovyDoc comment line can optionally start with a star *. Those comments are associated with:

  • type definitions (classes, interfaces, enums, annotations),

  • fields and properties definitions

  • methods definitions

Although the compiler will not complain about GroovyDoc comments not being associated with the above language elements, you should prepend those constructs with the comment right before it.

/**
 * A Class description
 */
class Person {
    /** the name of the person */
    String name

    /**
     * Creates a greeting method for a certain person.
     *
     * @param otherPerson the person to greet
     * @return a greeting message
     */
    String greet(String otherPerson) {
       "Hello ${otherPerson}"
    }
}

GroovyDoc follows the same conventions as Java’s own JavaDoc. So you’ll be able to use the same tags as with JavaDoc.

Shebang line

Beside the single line comment, there is a special line comment, often called the shebang line understood by UNIX systems which allows scripts to be run directly from the command-line, provided you have installed the Groovy distribution and the groovy command is available on the PATH.

#!/usr/bin/env groovy
println "Hello from the shebang line"
The # character must be the first character of the file. Any indentation would yield a compilation error.

1.1.2. Keywords

The following list represents all the keywords of the Groovy language:

Table 1. Keywords

as

assert

break

case

catch

class

const

continue

def

default

do

else

enum

extends

false

finally

for

goto

if

implements

import

in

instanceof

interface

new

null

package

return

super

switch

this

throw

throws

trait

true

try

while

1.1.3. Identifiers

Normal identifiers

Identifiers start with a letter, a dollar or an underscore. They cannot start with a number.

A letter can be in the following ranges:

  • 'a' to 'z' (lowercase ascii letter)

  • 'A' to 'Z' (uppercase ascii letter)

  • '\u00C0' to '\u00D6'

  • '\u00D8' to '\u00F6'

  • '\u00F8' to '\u00FF'

  • '\u0100' to '\uFFFE'

Then following characters can contain letters and numbers.

Here are a few examples of valid identifiers (here, variable names):

def name
def item3
def with_underscore
def $dollarStart

But the following ones are invalid identifiers:

def 3tier
def a+b
def a#b

All keywords are also valid identifiers when following a dot:

foo.as
foo.assert
foo.break
foo.case
foo.catch
Quoted identifiers

Quoted identifiers appear after the dot of a dotted expression. For instance, the name part of the person.name expression can be quoted with person."name" or person.'name'. This is particularly interesting when certain identifiers contain illegal characters that are forbidden by the Java Language Specification, but which are allowed by Groovy when quoted. For example, characters like a dash, a space, an exclamation mark, etc.

def map = [:]

map."an identifier with a space and double quotes" = "ALLOWED"
map.'with-dash-signs-and-single-quotes' = "ALLOWED"

assert map."an identifier with a space and double quotes" == "ALLOWED"
assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"

As we shall see in the following section on strings, Groovy provides different string literals. All kind of strings are actually allowed after the dot:

map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$

There’s a difference between plain character strings and Groovy’s GStrings (interpolated strings), as in that the latter case, the interpolated values are inserted in the final string for evaluating the whole identifier:

def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"

assert map.'Simson-Homer' == "Homer Simson"

1.1.4. Strings

Text literals are represented in the form of chain of characters called strings. Groovy lets you instantiate java.lang.String objects, as well as GStrings (groovy.lang.GString) which are also called interpolated strings in other programming languages.

Single quoted string

Single quoted strings are a series of characters surrounded by single quotes:

'a single quoted string'
Single quoted strings are plain java.lang.String and don’t support interpolation.
String concatenation

All the Groovy strings can be concatenated with the + operator:

assert 'ab' == 'a' + 'b'
Triple single quoted string

Triple single quoted strings are a series of characters surrounded by triplets of single quotes:

'''a triple single quoted string'''
Triple single quoted strings are plain java.lang.String and don’t support interpolation.

Triple single quoted strings are multiline. You can span the content of the string across line boundaries without the need to split the string in several pieces, without contatenation or newline escape characters:

def aMultilineString = '''line one
line two
line three'''

If your code is indented, for example in the body of the method of a class, your string will contain the whitespace of the indentation. The Groovy Development Kit contains methods for stripping out the indentation with the String#stripIndent() method, and with the String#stripMargin() method that takes a delimiter character to identify the text to remove from the beginning of a string.

When creating a string as follows:

def startingAndEndingWithANewline = '''
line one
line two
line three
'''

You will notice that the resulting string contains a newline character as first character. It is possible to strip that character by escaping the newline with a backslash:

def strippedFirstNewline = '''\
line one
line two
line three
'''

assert !strippedFirstNewline.startsWith('\n')
Escaping special characters

You can escape single quotes with the the backslash character to avoid terminating the string literal:

'an escaped single quote: \' needs a backslash'

And you can escape the escape character itself with a double backslash:

'an escaped escape character: \\ needs a double backslash'

Some special characters also use the backslash as escape character:

Escape sequence Character

'\t'

tabulation

'\b'

backspace

'\n'

newline

'\r'

carriage return

'\f'

formfeed

'\\'

backslash

'\''

single quote (for single quoted and triple single quoted strings)

'\"'

double quote (for double quoted and triple double quoted strings)

Unicode escape sequence

For characters that are not present on your keyboard, you can use unicode escape sequences: a backslash, followed by 'u', then 4 hexadecimal digits.

For example, the Euro currency symbol can be represented with:

'The Euro currency symbol: \u20AC'
Double quoted string

Double quoted strings are a series of characters surrounded by double quotes:

"a double quoted string"
Double quoted strings are plain java.lang.String if there’s no interpolated expression, but are groovy.lang.GString instances if interpolation is present.
To escape a double quote, you can use the backslash character: "A double quote: \"".
String interpolation

Any Groovy expression can be interpolated in all string literals, apart from single and triple single quoted strings. Interpolation is the act of replacing a placeholder in the string with its value upon evaluation of the string. The placeholder expressions are surrounded by ${} or prefixed with $ for dotted expressions. The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling toString() on that expression.

Here, we have a string with a placeholder referencing a local variable:

def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"

assert greeting.toString() == 'Hello Guillaume'

But any Groovy expression is valid, as we can see in this example with an arithmetic expression:

def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5'
Not only expressions are actually allowed in between the ${} placeholder. Statements are also allowed, but a statement’s value is just null. So if several statements are inserted in that placeholder, the last one should somehow return a meaningful value to be inserted. For instance, "The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}" is supported and works as expected but a good practice is usually to stick to simple expressions inside GString placeholders.

In addition to ${} placeholders, we can also use a lone $ sign prefixing a dotted expression:

def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

But only dotted expressions of the form a.b, a.b.c, etc, are valid, but expressions that would contain parentheses like method calls, curly braces for closures, or arithmetic operators would be invalid. Given the following variable definition of a number:

def number = 3.14

The following statement will throw a groovy.lang.MissingPropertyException because Groovy believes you’re trying to access the toString property of that number, which doesn’t exist:

shouldFail(MissingPropertyException) {
    println "$number.toString()"
}
You can think of "$number.toString()" as being interpreted by the parser as "${number.toString}()".

If you need to escape the $ or ${} placeholders in a GString so they appear as is without interpolation, you just need to use a \ backslash character to escape the dollar sign:

assert '${name}' == "\${name}"
Special case of interpolating closure expressions

So far, we’ve seen we could interpolate arbitrary expressions inside the ${} placeholder, but there is a special case and notation for closure expressions. When the placeholder contains an arrow, ${→}, the expression is actually a closure expression — you can think of it as a closure with a dollar prepended in front of it:

def sParameterLessClosure = "1 + 2 == ${-> 3}" (1)
assert sParameterLessClosure == '1 + 2 == 3'

def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" (2)
assert sOneParamClosure == '1 + 2 == 3'
1 The closure is a parameterless closure which doesn’t take arguments.
2 Here, the closure takes a single java.io.StringWriter argument, to which you can append content with the << leftShift operator. In either case, both placeholders are embedded closures.

In appearance, it looks like a more verbose way of defining expressions to be interpolated, but closure have an interesting advantage over mere expressions: lazy evaluation.

Let’s consider the following sample:

def number = 1 (1)
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"

assert eagerGString == "value == 1" (2)
assert lazyGString ==  "value == 1" (3)

number = 2 (4)
assert eagerGString == "value == 1" (5)
assert lazyGString ==  "value == 2" (6)
1 We define a number variable containing 1 that we then interpolate within two GStrings, as an expression in eagerGString and as a closure in lazyGString.
2 We expect the resulting string to contain the same string value of 1 for eagerGString.
3 Similarly for lazyGString
4 Then we change the value of the variable to a new number
5 With a plain interpolated expression, the value was actually bound at the time of creation of the GString.
6 But with a closure expression, the closure is called upon each coercion of the GString into String, resulting in an updated string containing the new number value.
An embedded closure expression taking more than one parameter will generate an exception at runtime. Only closures with zero or one parameters are allowed.
Interoperability with Java

When a method (whether implemented in Java or Groovy) expects a java.lang.String, but we pass a groovy.lang.GString instance, the toString() method of the GString is automatically and transparently called.

String takeString(String message) {         (4)
    assert message instanceof String        (5)
    return message
}

def message = "The message is ${'hello'}"   (1)
assert message instanceof GString           (2)

def result = takeString(message)            (3)
assert result instanceof String
assert result == 'The message is hello'
1 We create a GString variable
2 We double check it’s an instance of the GString
3 We then pass that GString to a method taking a String as parameter
4 The signature of the takeString() method explicitly says its sole parameter is a String
5 We also verify that the parameter is indeed a String and not a GString.
GString and String hashCodes

Although interpolated strings can be used in lieu of plain Java strings, they differ with strings in a particular way: their hashCodes are different. Plain Java strings are immutable, whereas the resulting String representation of a GString can vary, depending on its interpolated values. Even for the same resulting string, GStrings and Strings don’t have the same hashCode.

assert "one: ${1}".hashCode() != "one: 1".hashCode()

GString and Strings having different hashCode values, using GString as Map keys should be avoided, especially if we try to retrieve an associated value with a String instead of a GString.

def key = "a"
def m = ["${key}": "letter ${key}"]     (1)

assert m["a"] == null                   (2)
1 The map is created with an initial pair whose key is a GString
2 When we try to fetch the value with a String key, we will not find it, as Strings and GString have different hashCode values
Triple double quoted string

Triple double quoted strings behave like double quoted strings, with the addition that they are multiline, like the triple single quoted strings.

def name = 'Groovy'
def template = """
    Dear Mr ${name},

    You're the winner of the lottery!

    Yours sincerly,

    Dave
"""

assert template.toString().contains('Groovy')
Neither double quotes nor single quotes need be escaped in triple double quoted strings.
Slashy string

Beyond the usual quoted strings, Groovy offers slashy strings, which use / as delimiters. Slashy strings are particularly useful for defining regular expressions and patterns, as there is no need to escape backslashes.

Example of a slashy string:

def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'

Only forward slashes need to be escaped with a backslash:

def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'

Slashy strings are multiline:

def multilineSlashy = /one
    two
    three/

assert multilineSlashy.contains('\n')

Slashy strings can also be interpolated (ie. a GString):

def color = 'blue'
def interpolatedSlashy = /a ${color} car/

assert interpolatedSlashy == 'a blue car'

There are a few gotchas to be aware of.

An empty slashy string cannot be represented with a double forward slash, as it’s understood by the Groovy parser as a line comment. That’s why the following assert would actually not compile as it would look like a non-terminated statement:

assert '' == //
Dollar slashy string

Dollar slashy strings are multiline GStrings delimited with an opening $/ and and a closing /$. The escaping character is the dollar sign, and it can escape another dollar, or a forward slash. But both dollar and forward slashes don’t need to be escaped, except to escape the dollar of a string subsequence that would start like a GString placeholder sequence, or if you need to escape a sequence that would start like a closing dollar slashy string delimiter.

Here’s an example:

def name = "Guillaume"
def date = "April, 1st"

def dollarSlashy = $/
    Hello $name,
    today we're ${date}.

    $ dollar sign
    $$ escaped dollar sign
    \ backslash
    / forward slash
    $/ escaped forward slash
    $/$ escaped dollar slashy string delimiter
/$

assert [
    'Guillaume',
    'April, 1st',
    '$ dollar sign',
    '$ escaped dollar sign',
    '\\ backslash',
    '/ forward slash',
        '$/ escaped forward slash',
        '/$ escaped dollar slashy string delimiter'

        ].each { dollarSlashy.contains(it) }
String summary table

String name

String syntax

Interpolated

Multiline

Escape character

Single quoted

'…​'

\

Triple single quoted

'''…​'''

\

Double quoted

"…​"

\

Triple double quoted

"""…​"""

\

Slashy

/…​/

\

Dollar slashy

$/…​/$

$

Characters

Unlike Java, Groovy doesn’t have an explicit character literal. However, you can be explicit about making a Groovy string an actual character, by three different means:

char c1 = 'A' (1)
assert c1 instanceof Character

def c2 = 'B' as char (2)
assert c2 instanceof Character

def c3 = (char)'C' (3)
assert c3 instanceof Character
1 by being explicit when declaring a variable holding the character by specifying the char type
2 by using type coercion with the as operator
3 by using a cast to char operation
The first option 1 is interesting when the character is held in a variable, while the other two (2 and 3) are more interesting when a char value must be passed as argument of a method call.

1.1.5. Numbers

Groovy supports different kinds of integral literals and decimal literals, backed by the usual Number types of Java.

Integral literals

The integral literal types are the same as in Java:

  • byte

  • char

  • short

  • int

  • long

  • java.lang.BigInteger

You can create integral numbers of those types with the following declarations:

// primitive types
byte  b = 1
char  c = 2
short s = 3
int   i = 4
long  l = 5

// infinite precision
BigInteger bi =  6

If you use optional typing by using the def keyword, the type of the integral number will vary: it’ll adapt to the capacity of the type that can hold that number.

For positive numbers:

def a = 1
assert a instanceof Integer

// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer

// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long

// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long

// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger

As well as for negative numbers:

def na = -1
assert na instanceof Integer

// Integer.MIN_VALUE
def nb = -2147483648
assert nb instanceof Integer

// Integer.MIN_VALUE - 1
def nc = -2147483649
assert nc instanceof Long

// Long.MIN_VALUE
def nd = -9223372036854775808
assert nd instanceof Long

// Long.MIN_VALUE - 1
def ne = -9223372036854775809
assert ne instanceof BigInteger
Alternative non-base 10 representations
Binary literal

In Java 6 and before, as well as in Groovy, numbers could be represented in decimal, octal and hexadecimal bases, and with Java 7 and Groovy 2, you can use a binary notation with the 0b prefix:

int xInt = 0b10101111
assert xInt == 175

short xShort = 0b11001001
assert xShort == 201 as short

byte xByte = 0b11
assert xByte == 3 as byte

long xLong = 0b101101101101
assert xLong == 2925l

BigInteger xBigInteger = 0b111100100001
assert xBigInteger == 3873g

int xNegativeInt = -0b10101111
assert xNegativeInt == -175
Octal literal

Octal numbers are specified in the typical format of 0 followed by octal digits.

int xInt = 077
assert xInt == 63

short xShort = 011
assert xShort == 9 as short

byte xByte = 032
assert xByte == 26 as byte

long xLong = 0246
assert xLong == 166l

BigInteger xBigInteger = 01111
assert xBigInteger == 585g

int xNegativeInt = -077
assert xNegativeInt == -63
Hexadecimal literal

Hexadecimal numbers are specified in the typical format of 0x followed by hex digits.

int xInt = 0x77
assert xInt == 119

short xShort = 0xaa
assert xShort == 170 as short

byte xByte = 0x3a
assert xByte == 58 as byte

long xLong = 0xffff
assert xLong == 65535l

BigInteger xBigInteger = 0xaaaa
assert xBigInteger == 43690g

Double xDouble = new Double('0x1.0p0')
assert xDouble == 1.0d

int xNegativeInt = -0x77
assert xNegativeInt == -119
Decimal literals

The decimal literal types are the same as in Java:

  • float

  • double

  • java.lang.BigDecimal

You can create decimal numbers of those types with the following declarations:

// primitive types
float  f = 1.234
double d = 2.345

// infinite precision
BigDecimal bd =  3.456

Decimals can use exponents, with the e or E exponent letter, followed by an optional sign, and a integral number representing the exponent:

assert 1e3  ==  1_000.0
assert 2E4  == 20_000.0
assert 3e+1 ==     30.0
assert 4E-2 ==      0.04
assert 5e-1 ==      0.5

Conveniently for exact decimal number calculations, Groovy choses java.lang.BigDecimal as its decimal number type. In addition, both float and double are supported, but require an explicit type declaration, type coercion or suffix. Even if BigDecimal is the default for decimal numbers, such literals are accepted in methods or closures taking float or double as parameter types.

Decimal numbers can’t be represented using a binary, octal or hexadecimal representation.
Underscore in literals

When writing long literal numbers, it’s harder on the eye to figure out how some numbers are grouped together, for example with groups of thousands, of words, etc. By allowing you to place underscore in number literals, it’s easier to spot those groups:

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
Number type suffixes

We can force a number (including binary, octals and hexadecimals) to have a specific type by giving a suffix (see table bellow), either uppercase or lowercase.

Type Suffix

BigInteger

G or g

Long

L or l

Integer

I or i

BigDecimal

G or g

Double

D or d

Float

F or f

Examples:

assert 42I == new Integer('42')
assert 42i == new Integer('42') // lowercase i more readable
assert 123L == new Long("123") // uppercase L more readable
assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')
assert 1.234F == new Float('1.234')
assert 1.23E23D == new Double('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal
Math operations

Although operators are covered later on, it’s important to discuss the behavior of math operations and what their resulting types are.

Division and power binary operations aside (covered below),

  • binary operations between byte, char, short and int result in int

  • binary operations involving long with byte, char, short and int result in long

  • binary operations involving BigInteger and any other integral type result in BigInteger

  • binary operations between float, double and BigDecimal result in double

  • binary operations between two BigDecimal result in BigDecimal

The following table summarizes those rules:

byte char short int long BigInteger float double BigDecimal

byte

int

int

int

int

long

BigInteger

double

double

double

char

int

int

int

long

BigInteger

double

double

double

short

int

int

long

BigInteger

double

double

double

int

int

long

BigInteger

double

double

double

long

long

BigInteger

double

double

double

BigInteger

BigInteger

double

double

double

float

double

double

double

double

double

double

BigDecimal

BigDecimal

Thanks Groovy’s operator overloading, the usual arithmetic operators work as well with BigInteger and BigDecimal, unlike in Java where you have to use explicit methods for operating on those numbers.
The case of the division operator

The division operators / (and /= for division and assignment) produce a double result if either operand is a float or double, and a BigDecimal result otherwise (when both operands are any combination of an integral type short, char, byte, int, long, BigInteger or BigDecimal).

BigDecimal division is performed with the divide() method if the division is exact (i.e. yielding a result that can be represented within the bounds of the same precision and scale), or using a MathContext with a precision of the maximum of the two operands' precision plus an extra precision of 10, and a scale of the maximum of 10 and the maximum of the operands' scale.

For integer division like in Java, you should use the intdiv() method, as Groovy doesn’t provide a dedicated integer division operator symbol.
The case of the power operator

The power operation is represented by the ** operator, with two parameters: the base and the exponent. The result of the power operation depends on its operands, and the result of the operation (in particular if the result can be represented as an integral value).

The following rules are used by Groovy’s power operation to determine the resulting type:

  • If the exponent is a decimal value

    • if the result can be represented as an Integer, then return an Integer

    • else if the result can be represented as a Long, then return a Long

    • otherwise return a Double

  • If the exponent is an integral value

    • if the exponent is strictly negative, then return an Integer, Long or Double if the result value fits in that type

    • if the exponent is positive or zero

      • if the base is a BigDecimal, then return a BigDecimal result value

      • if the base is a BigInteger, then return a BigInteger result value

      • if the base is an Integer, then return an Integer if the result value fits in it, otherwise a BigInteger

      • if the base is a Long, then return a Long if the result value fits in it, otherwise a BigInteger

We can illustrate those rules with a few examples:

// base and exponent are ints and the result can be represented by an Integer
assert    2    **   3    instanceof Integer    //  8
assert   10    **   9    instanceof Integer    //  1_000_000_000

// the base is a long, so fit the result in a Long
// (although it could have fit in an Integer)
assert    5L   **   2    instanceof Long       //  25

// the result can't be represented as an Integer or Long, so return a BigInteger
assert  100    **  10    instanceof BigInteger //  10e20
assert 1234    ** 123    instanceof BigInteger //  170515806212727042875...

// the base is a BigDecimal and the exponent a negative int
// but the result can be represented as an Integer
assert    0.5  **  -2    instanceof Integer    //  4

// the base is an int, and the exponent a negative float
// but again, the result can be represented as an Integer
assert    1    **  -0.3f instanceof Integer    //  1

// the base is an int, and the exponent a negative int
// but the result will be calculated as a Double
// (both base and exponent are actually converted to doubles)
assert   10    **  -1    instanceof Double     //  0.1

// the base is a BigDecimal, and the exponent is an int, so return a BigDecimal
assert    1.2  **  10    instanceof BigDecimal //  6.1917364224

// the base is a float or double, and the exponent is an int
// but the result can only be represented as a Double value
assert    3.4f **   5    instanceof Double     //  454.35430372146965
assert    5.6d **   2    instanceof Double     //  31.359999999999996

// the exponent is a decimal value
// and the result can only be represented as a Double value
assert    7.8  **   1.9  instanceof Double     //  49.542708423868476
assert    2    **   0.1f instanceof Double     //  1.0717734636432956

1.1.6. Booleans

Boolean is a special data type that is used to represent truth values: true and false. Use this data type for simple flags that track true/false conditions.

Boolean values can be stored in variables, assigned into fields, just like any other data type:

def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true

true and false are the only two primitive boolean values. But more complex boolean expressions can be represented using logical operators.

In addition, Groovy has special rules (often referred to as Groovy Truth) for coercing non-boolean objects to a boolean value.

1.1.7. Lists

Groovy uses a comma-separated list of values, surrounded by square brackets, to denote lists. Groovy lists are plain JDK java.util.List, as Groovy doesn’t define its own collection classes. The concrete list implementation used when defining list literals are java.util.ArrayList by default, unless you decide to specify otherwise, as we shall see later on.

def numbers = [1, 2, 3]         (1)

assert numbers instanceof List  (2)
assert numbers.size() == 3      (3)
1 We define a list numbers delimited by commas and surrounded by square brackets, and we assign that list into a variable
2 The list is an instance of Java’s java.util.List interface
3 The size of the list can be queried with the size() method, and shows our list contains 3 elements

In the above example, we used a homogeneous list, but you can also create lists containing values of heterogeneous types:

def heterogeneous = [1, "a", true]  (1)
1 Our list here contains a number, a string and a boolean value

We mentioned that by default, list literals are actually instances of java.util.ArrayList, but it is possible to use a different backing type for our lists, thanks to using type coercion with the as operator, or with explicit type declaration for your variables:

def arrayList = [1, 2, 3]
assert arrayList instanceof java.util.ArrayList

def linkedList = [2, 3, 4] as LinkedList    (1)
assert linkedList instanceof java.util.LinkedList

LinkedList otherLinked = [3, 4, 5]          (2)
assert otherLinked instanceof java.util.LinkedList
1 We use coercion with the as operator to explicitly request a java.util.LinkedList implementation
2 We can say that the variable holding the list literal is of type java.util.LinkedList

You can access elements of the list with the [] subscript operator (both for reading and setting values) with positive indices or negative indices to access elements from the end of the list, as well as with ranges, and use the << leftShift operator to append elements to a list:

def letters = ['a', 'b', 'c', 'd']

assert letters[0] == 'a'     (1)
assert letters[1] == 'b'

assert letters[-1] == 'd'    (2)
assert letters[-2] == 'c'

letters[2] = 'C'             (3)
assert letters[2] == 'C'

letters << 'e'               (4)
assert letters[ 4] == 'e'
assert letters[-1] == 'e'

assert letters[1, 3] == ['b', 'd']         (5)
assert letters[2..4] == ['C', 'd', 'e']    (6)
1 Access the first element of the list (zero-based counting)
2 Access the last element of the list with a negative index: -1 is the first element from the end of the list
3 Use an assignment to set a new value for the third element of the list
4 Use the << leftShift operator to append an element at the end of the list
5 Access two elements at once, returning a new list containing those two elements
6 Use a range to access a range of values from the list, from a start to an end element position

As lists can be heterogeneous in nature, lists can also contain other lists to create multi-dimensional lists:

def multi = [[0, 1], [2, 3]]     (1)
assert multi[1][0] == 2          (2)
1 Define a list of list of numbers
2 Access the second element of the top-most list, and the first element of the inner list

1.1.8. Arrays

Groovy reuses the list notation for arrays, but to make such literals arrays, you need to explicitely define the type of the array through coercion or type declaration.

String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  (1)

assert arrStr instanceof String[]    (2)
assert !(arrStr instanceof List)

def numArr = [1, 2, 3] as int[]      (3)

assert numArr instanceof int[]       (4)
assert numArr.size() == 3
1 Define an array of strings using explicit variable type declaration
2 Assert that we created an array of strings
3 Create an array of ints with the as operator
4 Assert that we created an array of primitive ints

You can also create multi-dimensional arrays:

def matrix3 = new Integer[3][3]         (1)
assert matrix3.size() == 3

Integer[][] matrix2                     (2)
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]
1 You can define the bounds of a new array
2 Or declare an array without specifying its bounds

Access to elements of an array follows the same notation as for lists:

String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
assert names[0] == 'Cédric'     (1)

names[2] = 'Blackdrag'          (2)
assert names[2] == 'Blackdrag'
1 Retrieve the first element of the array
2 Set the value of the third element of the array to a new value
Java’s array initializer notation is not supported by Groovy, as the curly braces can be misinterpreted with the notation of Groovy closures.

1.1.9. Maps

Sometimes called dictionaries or associative arrays in other languages, Groovy features maps. Maps associate keys to values, separating keys and values with colons, and each key/value pairs with commas, and the whole keys and values surrounded by square brackets.

def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']   (1)

assert colors['red'] == '#FF0000'    (2)
assert colors.green  == '#00FF00'    (3)

colors['pink'] = '#FF00FF'           (4)
colors.yellow  = '#FFFF00'           (5)

assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'

assert colors instanceof java.util.LinkedHashMap
1 We define a map of string color names, associated with their hexadecimal-coded html colors
2 We use the subscript notation to check the content associated with the red key
3 We can also use the property notation to assert the color green’s hexadecimal representation
4 Similarly, we can use the subscript notation to add a new key/value pair
5 Or the property notation, to add the yellow color
When using names for the keys, we actually define string keys in the map.
Groovy creates maps that are actually instances of java.util.LinkedHashMap.

If you try to access a key which is not present in the map:

assert colors.unknown == null

You will retrieve a null result.

In the examples above, we used string keys, but you can also use values of other types as keys:

def numbers = [1: 'one', 2: 'two']

assert numbers[1] == 'one'

Here, we used numbers as keys, as numbers can unambiguously be recognized as numbers, so Groovy will not create a string key like in our previous examples. But consider the case you want to pass a variable in lieu of the key, to have the value of that variable become the key:

def key = 'name'
def person = [key: 'Guillaume']      (1)

assert !person.containsKey('name')   (2)
assert person.containsKey('key')     (3)
1 The key associated with the 'Guillaume' name will actually be the "key" string, not the value associated with the key variable
2 The map doesn’t contain the 'name' key
3 Instead, the map contains a 'key' key
You can also pass quoted strings as well as keys: ["name": "Guillaume"]. This is mandatory if your key string isn’t a valid identifier, for example if you wanted to create a string key containing a hash like in: ["street-name": "Main street"].

When you need to pass variable values as keys in your map definitions, you must surround the variable or expression with parentheses:

person = [(key): 'Guillaume']        (1)

assert person.containsKey('name')    (2)
assert !person.containsKey('key')    (3)
1 This time, we surround the key variable with parentheses, to instruct the parser we are passing a variable rather than defining a string key
2 The map does contain the name key
3 But the map doesn’t contain the key key as before

1.2. Operators

This chapter covers the operators of the Groovy programming language.

1.2.1. Arithmetic operators

Groovy supports the usual familiar arithmetic operators you find in mathematics and in other programming languages like Java. All the Java arithmetic operators are supported. Let’s go through them in the following examples.

Normal arithmetic operators

The following binary arithmetic operators are available in Groovy:

Operator Purpose Remarks

+

addition

-

subtraction

*

multiplication

/

division

Use intdiv() for integer division, and see the section about integer division for more information on the return type of the division.

%

modulo

**

power

See the section about the power operation for more information on the return type of the operation.

Here are a few examples of usage of those operators:

assert  1  + 2 == 3
assert  4  - 3 == 1
assert  3  * 5 == 15
assert  3  / 2 == 1.5
assert 10  % 3 == 1
assert  2 ** 3 == 8
Unary operators

The + and - operators are also available as unary operators:

assert +3 == 3
assert -4 == 0 - 4

assert -(-1) == 1  (1)
1 Note the usage of parentheses to surround an expression to apply the unary minus to that surrounded expression.

In terms of unary arithmetics operators, the ++ (increment) and -- (decrement) operators are available, both in prefix and postfix notation:

def a = 2
def b = a++ * 3             (1)

assert a == 3 && b == 6

def c = 3
def d = c-- * 2             (2)

assert c == 2 && d == 6

def e = 1
def f = ++e + 3             (3)

assert e == 2 && f == 5

def g = 4
def h = --g + 1             (4)

assert g == 3 && h == 4
1 The postfix increment will increment a after the expression has been evaluated and assigned into b
2 The postfix decrement will decrement c after the expression has been evaluated and assigned into d
3 The prefix increment will increment e before the expression is evaluated and assigned into f
4 The prefix decrement will decrement g before the expression is evaluated and assigned into h
Assignment arithmetic operators

The binary arithmetic operators we have seen above are also available in an assignment form:

  • +=

  • -=

  • *=

  • /=

  • %=

  • **=

Let’s see them in action:

def a = 4
a += 3

assert a == 7

def b = 5
b -= 3

assert b == 2

def c = 5
c *= 3

assert c == 15

def d = 10
d /= 2

assert d == 5

def e = 10
e %= 3

assert e == 1

def f = 3
f **= 2

assert f == 9

1.2.2. Relational operators

Relational operators allow comparisons between objects, to know if two objects are the same or different, or if one is greater than, less than, or equal to the other.

The following operators are available:

Operator Purpose

==

equal

!=

different

<

less than

<=

less than or equal

>

greater than

>=

greater than or equal

Here are some examples of simple number comparisons using these operators:

assert 1 + 2 == 3
assert 3 != 4

assert -2 < 3
assert 2 <= 2
assert 3 <= 4

assert 5 > 1
assert 5 >= -2

1.2.3. Logical operators

Groovy offers three logical operators for boolean expressions:

  • &&: logical "and"

  • ||: logical "or"

  • !: logical "not"

Let’s illustrate them with the following examples:

assert !false           (1)
assert true && true     (2)
assert true || false    (3)
1 "not" false is true
2 true "and" true is true
3 true "or" false is true
Precedence

The logical "not" has a higher priority than the logical "and".

assert (!false && false) == false   (1)
1 Here, the assertion is true (as the expression in parentheses is false), because "not" has a higher precedence than "and", so it only applies to the first "false" term; otherwise, it would have applied to the result of the "and", turned it into true, and the assertion would have failed

The logical "and" has a higher priority than the logical "or".

assert true || true && false        (1)
1 Here, the assertion is true, because "and" has a higher precedence than "or", therefore the "or" is executed last and returns true, having one true argument; otherwise, the "and" would have executed last and returned false, having one false argument, and the assertion would have failed
Short-circuiting

The logical || operator supports short-circuiting: if the left operand is true, it knows that the result will be true in any case, so it won’t evaluate the right operand. The right operand will be evaluated only if the left operand is false.

Likewise for the logical && operator: if the left operand is false, it knows that the result will be false in any case, so it won’t evaluate the right operand. The right operand will be evaluated only if the left operand is true.

boolean checkIfCalled() {   (1)
    called = true
}

called = false
true || checkIfCalled()
assert !called              (2)

called = false
false || checkIfCalled()
assert called               (3)

called = false
false && checkIfCalled()
assert !called              (4)

called = false
true && checkIfCalled()
assert called               (5)
1 We create a function that sets the called flag to true whenever it’s called
2 In the first case, after resetting the called flag, we confirm that if the left operand to || is true, the function is not called, as || short-circuits the evaluation of the right operand
3 In the second case, the left operand is false and so the function is called, as indicated by the fact our flag is now true
4 Likewise for &&, we confirm that the function is not called with a false left operand
5 But the function is called with a true left operand

1.2.4. Bitwise operators

Groovy offers 4 bitwise operators:

  • &: bitwise "and"

  • |: bitwise "or"

  • ^: bitwise "xor" (exclusive "or")

  • ~: bitwise negation

Bitwise operators can be applied on a byte or an int and return an int:

int a = 0b00101010
assert a==42
int b = 0b00001000
assert b==8
assert (a & a) == a                     (1)
assert (a & b) == b                     (2)
assert (a | a) == a                     (3)
assert (a | b) == a                     (4)

int mask = 0b11111111                   (5)
assert ((a ^ a) & mask) == 0b00000000   (6)
assert ((a ^ b) & mask) == 0b00100010   (7)
assert ((~a) & mask)    == 0b11010101   (8)
1 bitwise and
2 bitwise and returns common bits
3 bitwise or
4 bitwise or returns all '1' bits
5 setting a mask to check only the last 8 bits
6 bitwise exclusive or on self returns 0
7 bitwise exclusive or
8 bitwise negation

It’s worth noting that the internal representation of primitive types follow the Java Language Specification. In particular, primitive types are signed, meaning that for a bitwise negation, it is always good to use a mask to retrieve only the necessary bits.

In Groovy, bitwise operators have the particularity of being overloadable, meaning that you can define the behavior of those operators for any kind of object.

1.2.5. Conditional operators

Not operator

The "not" operator is represented with an exclamation mark (!) and inverts the result of the underlying boolean expression. In particular, it is possible to combine the not operator with the Groovy truth:

assert (!true)    == false                      (1)
assert (!'foo')   == false                      (2)
assert (!'')      == true                       (3)
1 the negation of true is false
2 'foo' is a non empty string, evaluating to true, so negation returns false
3 '' is an empty string, evaluating to false, so negation returns true
Ternary operator

The ternary operator is a shortcut expression that is equivalent to an if/else branch assigning some value to a variable.

Instead of:

if (string!=null && string.length()>0) {
    result = 'Found'
} else {
    result = 'Not found'
}

You can write:

result = (string!=null && string.length()>0) ? 'Found' : 'Not found'

The ternary operator is also compatible with the Groovy truth, so you can make it even simpler:

result = string ? 'Found' : 'Not found'
Elvis operator

The "Elvis operator" is a shortening of the ternary operator. One instance of where this is handy is for returning a 'sensible default' value if an expression resolves to false-ish (as in Groovy truth). A simple example might look like this:

displayName = user.name ? user.name : 'Anonymous'   (1)
displayName = user.name ?: 'Anonymous'              (2)
1 with the ternary operator, you have to repeat the value you want to assign
2 with the Elvis operator, the value, which is tested, is used if it is not false-ish

Usage of the Elvis operator reduces the verbosity of your code and reduces the risks of errors in case of refactorings, by removing the need to duplicate the expression which is tested in both the condition and the positive return value.

1.2.6. Object operators

Safe navigation operator

The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception, like so:

def person = Person.find { it.id == 123 }    (1)
def name = person?.name                      (2)
assert name == null                          (3)
1 find will return a null instance
2 use of the null-safe operator prevents from a NullPointerException
3 result is null
Direct field access operator

Normally in Groovy, when you write code like this:

class User {
    public final String name                 (1)
    User(String name) { this.name = name}
    String getName() { "Name: $name" }       (2)
}
def user = new User('Bob')
assert user.name == 'Name: Bob'              (3)
1 public field name
2 a getter for name that returns a custom string
3 calls the getter

The user.name call triggers a call to the property of the same name, that is to say, here, to the getter for name. If you want to retrieve the field instead of calling the getter, you can use the direct field access operator:

assert user.@name == 'Bob'                   (1)
1 use of .@ forces usage of the field instead of the getter
Method pointer operator

The method pointer operator (.&) call be used to store a reference to a method in a variable, in order to call it later:

def str = 'example of method reference'            (1)
def fun = str.&toUpperCase                         (2)
def upper = fun()                                  (3)
assert upper == str.toUpperCase()                  (4)
1 the str variable contains a String
2 we store a reference to the toUpperCase method on the str instance inside a variable named fun
3 fun can be called like a regular method
4 we can check that the result is the same as if we had called it directly on str

There are multiple advantages in using method pointers. First of all, the type of such a method pointer is a groovy.lang.Closure, so it can be used in any place a closure would be used. In particular, it is suitable to convert an existing method for the needs of the strategy pattern:

def transform(List elements, Closure action) {                    (1)
    def result = []
    elements.each {
        result << action(it)
    }
    result
}
String describe(Person p) {                                       (2)
    "$p.name is $p.age"
}
def action = this.&describe                                       (3)
def list = [
    new Person(name: 'Bob',   age: 42),
    new Person(name: 'Julia', age: 35)]                           (4)
assert transform(list, action) == ['Bob is 42', 'Julia is 35']    (5)
1 the transform method takes each element of the list and calls the action closure on them, returning a new list
2 we define a function that takes a Person a returns a String
3 we create a method pointer on that function
4 we create the list of elements we want to collect the descriptors
5 the method pointer can be used where a Closure was expected

Method pointers are bound by the receiver and a method name. Arguments are resolved at runtime, meaning that if you have multiple methods with the same name, the syntax is not different, only resolution of the appropriate method to be called will be done at runtime:

def doSomething(String str) { str.toUpperCase() }    (1)
def doSomething(Integer x) { 2*x }                   (2)
def reference = this.&doSomething                    (3)
assert reference('foo') == 'FOO'                     (4)
assert reference(123)   == 246                       (5)
1 define an overloaded doSomething method accepting a String as an argument
2 define an overloaded doSomething method accepting an Integer as an argument
3 create a single method pointer on doSomething, without specifying argument types
4 using the method pointer with a String calls the String version of doSomething
5 using the method pointer with an Integer calls the Integer version of doSomething

1.2.7. Regular expression operators

Pattern operator

The pattern operator (~) provides a simple way to create a java.util.regex.Pattern instance:

def p = ~/foo/
assert p instanceof Pattern

while in general, you find the pattern operator with an expression in a slashy-string, it can be used with any kind of String in Groovy:

p = ~'foo'                                                        (1)
p = ~"foo"                                                        (2)
p = ~$/dollar/slashy $ string/$                                   (3)
p = ~"${pattern}"                                                 (4)
1 using single quote strings
2 using double quotes strings
3 the dollar-slashy string lets you use slashes and the dollar sign without having to escape them
4 you can also use a GString!
Find operator

Alternatively to building a pattern, you can directly use the find operator =~ to build a java.util.regex.Matcher instance:

def text = "some text to match"
def m = text =~ /match/                                           (1)
assert m instanceof Matcher                                       (2)
if (!m) {                                                         (3)
    throw new RuntimeException("Oops, text not found!")
}
1 =~ creates a matcher against the text variable, using the pattern on the right hand side
2 the return type of =~ is a Matcher
3 equivalent to calling if (!m.find())

Since a Matcher coerces to a boolean by calling its find method, the =~ operator is consistent with the simple use of Perl’s =~ operator, when it appears as a predicate (in if, while, etc.).

Match operator

The match operator (==~) is a slight variation of the find operator, that does not return a Matcher but a boolean and requires a strict match of the input string:

m = text ==~ /match/                                              (1)
assert m instanceof Boolean                                       (2)
if (m) {                                                          (3)
    throw new RuntimeException("Should not reach that point!")
}
1 ==~ matches the subject with the regular expression, but match must be strict
2 the return type of ==~ is therefore a boolean
3 equivalent to calling if (text ==~ /match/)

1.2.8. Other operators

Spread operator

The Spread Operator (*.) is used to invoke an action on all items of an aggregate object. It is equivalent to calling the action on each item and collecting the result into a list:

class Car {
    String make
    String model
}
def cars = [
       new Car(make: 'Peugeot', model: '508'),
       new Car(make: 'Renault', model: 'Clio')]       (1)
def makes = cars*.make                                (2)
assert makes == ['Peugeot', 'Renault']                (3)
1 build a list of Car items. The list is an aggregate of objects.
2 call the spread operator on the list, accessing the make property of each item
3 returns a list of strings corresponding to the collection of make items

The spread operator is null-safe, meaning that if an element of the collection is null, it will return null instead of throwing a NullPointerException:

cars = [
   new Car(make: 'Peugeot', model: '508'),
   null,                                              (1)
   new Car(make: 'Renault', model: 'Clio')]
assert cars*.make == ['Peugeot', null, 'Renault']     (2)
assert null*.make == null                             (3)
1 build a list for which of of the elements is null
2 using the spread operator will not throw a NullPointerException
3 the receiver might also be null, in which case the return value is null

The spread operator can be used on any class which implements the Iterable interface:

class Component {
    Long id
    String name
}
class CompositeObject implements Iterable<Component> {
    def components = [
        new Component(id: 1, name: 'Foo'),
        new Component(id: 2, name: 'Bar')]

    @Override
    Iterator<Component> iterator() {
        components.iterator()
    }
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']
Spreading method arguments

There may be situations when the arguments of a method call can be found in a list that you need to adapt to the method arguments. In such situations, you can use the spread operator to call the method. For example, imagine you have the following method signature:

int function(int x, int y, int z) {
    x*y+z
}

then if you have the following list:

def args = [4,5,6]

you can call the method without having to define intermediate variables:

assert function(*args) == 26

It is even possible to mix normal arguments with spread ones:

args = [4]
assert function(*args,5,6) == 26
Spread list elements

When used inside a list literal, the spread operator acts as if the spread element contents were inlined into the list:

def items = [4,5]                      (1)
def list = [1,2,3,*items,6]            (2)
assert list == [1,2,3,4,5,6]           (3)
1 items is a list
2 we want to insert the contents of the items list directly into list without having to call addAll
3 the contents of items has been inlined into list
Spread map elements

The spread map operator works in a similar manner as the spread list operator, but for maps. It allows you to inline the contents of a map into another map literal, like in the following example:

def m1 = [c:3, d:4]                   (1)
def map = [a:1, b:2, *:m1]            (2)
assert map == [a:1, b:2, c:3, d:4]    (3)
1 m1 is the map that we want to inline
2 we use the *:m1 notation to spread the contents of m1 into map
3 map contains all the elements of m1

The position of the spread map operator is relevant, like illustrated in the following example:

def m1 = [c:3, d:4]                   (1)
def map = [a:1, b:2, *:m1, d: 8]      (2)
assert map == [a:1, b:2, c:3, d:8]    (3)
1 m1 is the map that we want to inline
2 we use the :m1 notation to spread the contents of m1 into map, but redefine the key d *after spreading
3 map contains all the expected keys, but d was redefined
Range operator

Groovy supports the concept of ranges and provides a notation (..) to create ranges of objects:

def range = 0..5                                    (1)
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]       (2)
assert (0..<5).collect() == [0, 1, 2, 3, 4]         (3)
assert (0..5) instanceof List                       (4)
assert (0..5).size() == 6                           (5)
1 a simple range of integers, stored into a local variable
2 an IntRange, with inclusive bounds
3 an IntRange, with exclusive upper bound
4 a groovy.lang.Range implements the List interface
5 meaning that you can call the size method on it

Ranges implementation is lightweight, meaning that only the lower and upper bounds are stored. You can create a range from any Comparable object. For example, you can create a range of characters this way:

assert ('a'..'d').collect() == ['a','b','c','d']
Spaceship operator

The spaceship operator (<=>) delegates to the compareTo method:

assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
Subscript operator

The subscript operator is a short hand notation for getAt or putAt, depending on whether you find it on the left hand side or the right hand side of an assignment:

def list = [0,1,2,3,4]
assert list[2] == 2                         (1)
list[2] = 4                                 (2)
assert list[0..2] == [0,1,4]                (3)
list[0..2] = [6,6,6]                        (4)
assert list == [6,6,6,3,4]                  (5)
1 [2] can be used instead of getAt(2)
2 if on left hand side of an assignment, will call putAt
3 getAt also supports ranges
4 so does putAt
5 the list is mutated

The subscript operator, in combination with a custom implementation of getAt/putAt is a convenient way for destructuring objects:

class User {
    Long id
    String name
    def getAt(int i) {                                             (1)
        switch (i) {
            case 0: return id
            case 1: return name
        }
        throw new IllegalArgumentException("No such element $i")
    }
    void putAt(int i, def value) {                                 (2)
        switch (i) {
            case 0: id = value; return
            case 1: name = value; return
        }
        throw new IllegalArgumentException("No such element $i")
    }
}
def user = new User(id: 1, name: 'Alex')                           (3)
assert user[0] == 1                                                (4)
assert user[1] == 'Alex'                                           (5)
user[1] = 'Bob'                                                    (6)
assert user.name == 'Bob'                                          (7)
1 the User class defines a custom getAt implementation
2 the User class defines a custom putAt implementation
3 create a sample user
4 using the subscript operator with index 0 allows retrieving the user id
5 using the subscript operator with index 1 allows retrieving the user name
6 we can use the subscript operator to write to a property thanks to the delegation to putAt
7 and check that it’s really the property name which was changed
Membership operator

The membership operator (in) is equivalent to calling the isCase method. In the context of a List, it is equivalent to calling contains, like in the following example:

def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)                     (1)
1 equivalent to calling list.contains('Emmy') or list.isCase('Emmy')
Identity operator

In Groovy, using == to test equality is different from using the same operator in Java. In Groovy, it is calling equals. If you want to compare reference equality, you should use is like in the following example:

def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        (1)
def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        (2)
assert list1 == list2                                       (3)
assert !list1.is(list2)                                     (4)
1 Create a list of strings
2 Create another list of strings containing the same elements
3 using ==, we test object equality
4 but using is, we can check that references are distinct
Coercion operator

The coercion operator (as) is a variant of casting. Coercion converts object from one type to another without them being compatible for assignment. Let’s take an example:

Integer x = 123
String s = (String) x                                   (1)
1 Integer is not assignable to a String, so it will produce a ClassCastException at runtime

This can be fixed by using coercion instead:

Integer x = 123
String s = x as String                                  (1)
1 Integer is not assignable to a String, but use of as will coerce it to a String

When an object is coerced into another, unless the target type is the same as the source type, coercion will return a new object. The rules of coercion differ depending on the source and target types, and coercion may fail if no conversion rules are found. Custom conversion rules may be implemented thanks to the asType method:

class Identifiable {
    String name
}
class User {
    Long id
    String name
    def asType(Class target) {                                              (1)
        if (target==Identifiable) {
            return new Identifiable(name: name)
        }
        throw new ClassCastException("User cannot be coerced into $target")
    }
}
def u = new User(name: 'Xavier')                                            (2)
def p = u as Identifiable                                                   (3)
assert p instanceof Identifiable                                            (4)
assert !(p instanceof User)                                                 (5)
1 the User class defines a custom conversion rule from User to Identifiable
2 we create an instance of User
3 we coerce the User instance into an Identifiable
4 the target is an instance of Identifiable
5 the target is not an instance of User anymore
Diamond operator

The diamond operator (<>) is a syntactic sugar only operator added to support compatibility with the operator of the same name in Java 7. It is used to indicate that generic types should be inferred from the declaration:

List<String> strings = new LinkedList<>()

In dynamic Groovy, this is totally unused. In statically type checked Groovy, it is also optional since the Groovy type checker performs type inference whether this operator is present or not.

Call operator

The call operator () is used to call a method named call implicitly. For any object which defines a call method, you can omit the .call part and use the call operator instead:

class MyCallable {
    int call(int x) {           (1)
        2*x
    }
}

def mc = new MyCallable()
assert mc.call(2) == 4          (2)
assert mc(2) == 4               (3)
1 MyCallable defines a method named call. Note that it doesn’t need to implement java.util.concurrent.Callable
2 we can call the method using the classic method call syntax
3 or we can omit .call thanks to the call operator

1.2.9. Operator precedence

The table below lists all groovy operators in order of precedence.

Level Operator(s) Name(s)

1

new   ()

object creation, explicit parentheses

()   {}   []

method call, closure, literal list/map

.   .&   .@

member access, method closure, field/attribute access

?.   *   *.   *:

safe dereferencing, spread, spread-dot, spread-map

~   !   (type)

bitwise negate/pattern, not, typecast

[]   ++   --

list/map/array index, post inc/decrement

2

**

power

3

++   --   +   -

pre inc/decrement, unary plus, unary minus

4

*   /   %

multiply, div, modulo

5

+   -

addition, subtraction

6

<<   >>   >>>   ..   ..<

left/right (unsigned) shift, inclusive/exclusive range

7

<   <=   >   >=   in   instanceof   as

less/greater than/or equal, in, instanceof, type coercion

8

==   !=   <=>

equals, not equals, compare to

=~   ==~

regex find, regex match

9

&

binary/bitwise and

10

^

binary/bitwise xor

11

|

binary/bitwise or

12

&&

logical and

13

||

logical or

14

? :

ternary conditional

?:

elvis operator

15

=   **=   *=   /=   %=   +=   -=  
<<=   >>=   >>>=   &=   ^=   |=

various assignments

1.2.10. Operator overloading

Groovy allows you to overload the various operators so that they can be used with your own classes. Consider this simple class:

class Bucket {
    int size

    Bucket(int size) { this.size = size }

    Bucket plus(Bucket other) {                     (1)
        return new Bucket(this.size + other.size)
    }
}
1 Bucket implements a special method called plus()

Just by implementing the plus() method, the Bucket class can now be used with the + operator like so:

def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15                         (1)
1 The two Bucket objects can be added together with the + operator

All (non-comparator) Groovy operators have a corresponding method that you can implement in your own classes. The only requirements are that your method is public, has the correct name, and has the correct number of arguments. The argument types depend on what types you want to support on the right hand side of the operator. For example, you could support the statement

assert (b1 + 11).size == 15

by implementing the plus() method with this signature:

Bucket plus(int capacity) {
    return new Bucket(this.size + capacity)
}

Here is a complete list of the operators and their corresponding methods:

Operator Method Operator Method

+

a.plus(b)

a[b]

a.getAt(b)

-

a.minus(b)

a[b] = c

a.putAt(b, c)

*

a.multiply(b)

<<

a.leftShift(b)

/

a.div(b)

>>

a.rightShift(b)

%

a.mod(b)

++

a.next()

**

a.power(b)

--

a.previous()

|

a.or(b)

+a

a.positive()

&

a.and(b)

-a

a.negative()

^

a.xor(b)

~a

a.bitwiseNegative()

1.3. Program structure

This chapter covers the program structure of the Groovy programming language.

1.3.1. Package names

Package names play exactly the same role as in Java. They allows us to separate the code base without any conflicts. Groovy classes must specify their package before the class definition, else the default package is assumed.

Defining a package is very similar to Java:

// defining a package named com.yoursite
package com.yoursite

To refer to some class Foo in the com.yoursite.com package you will need to use the fully qualified name com.yoursite.com.Foo, or else you can use an import statement as we’ll see below.

1.3.2. Imports

In order to refer to any class you need a qualified reference to its package. Groovy follows Java’s notion of allowing import statement to resolve class references.

For example, Groovy provides several builder classes, such as MarkupBuilder. MarkupBuilder is inside the package groovy.xml so in order to use this class, you need to import it as shown:

// importing the class MarkupBuilder
import groovy.xml.MarkupBuilder

// using the imported class to create an object
def xml = new MarkupBuilder()

assert xml != null
Default imports

Default imports are the imports that Groovy language provides by default. For example look at the following code:

new Date()

The same code in Java needs an import statement to Date class like this: import java.util.Date. Groovy by default imports these classes for you. There are six packages that groovy imports for you, they are:

import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
Simple import

A simple import is an import statement where you fully define the class name along with the package. For example the import statement import groovy.xml.MarkupBuilder in the code below is a simple import which directly refers to a class inside a package.

// importing the class MarkupBuilder
import groovy.xml.MarkupBuilder

// using the imported class to create an object
def xml = new MarkupBuilder()

assert xml != null
Star import

Groovy, like Java, provides a special way to import all classes from a package using *, a so called Star import. MarkupBuilder is a class which is in package groovy.xml, alongside another class called StreamingMarkupBuilder. In case you need to use both classes, you can do:

import groovy.xml.MarkupBuilder
import groovy.xml.StreamingMarkupBuilder

def markupBuilder = new MarkupBuilder()

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

That’s perfectly valid code. But with a import, we can achieve the same effect with just one line, where imports all the classes under package groovy.xml:

import groovy.xml.*

def markupBuilder = new MarkupBuilder()

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

One problem with * imports is that they can clutter your local namespace. But with the kinds of aliasing provided by Groovy, this can be solved easily.

Static import

Groovy’s static import capability allows you to reference imported classes as if they were static methods in your own class. This is similar to Java’s static import capability but works with Java 1.4 and above and is a little more dynamic than Java in that it allows you to define methods with the same name as an imported method as long as you have different types. If you have the same types, the imported class takes precedence. Here is a sample of its usage:

import static Boolean.FALSE

assert !FALSE //use directly, without Boolean prefix!

As you can see, now we can able to refer to the static variable FALSE in our code base cleanly.

Static import aliasing

Static imports with the as keyword provide an elegant solution to namespace problems. Suppose you want to get a Calendar instance, using its getInstance() method. It’s a static method, so we can use a static import. But instead of calling getInstance() every time, which can be misleading when separated from its class name, we can import it with an alias, to increase code readability:

import static Calendar.getInstance as now

assert now().class == Calendar.getInstance().class

Now, that’s clean!

Static star import

A static star import is very similar to the regular star import. It will import all the static methods from the given class.

For example, lets say we need to calculate sines and cosines for our application. The class java.lang.Math has static methods named sin and cos which fit our need. With the help of a static star import, we can do:

import static java.lang.Math.*

assert sin(0) == 0.0
assert cos(0) == 1.0

As you can see, we were able to access the methods sin and cos directly, without the Math. prefix.

Import aliasing

With type aliasing, we can refer to a fully qualified class name using a name of our choice. This can be done with the as keyword, as before.

Consider the following class, provided by some third-party library code:

package thirdpartylib

public class MultiplyTwo {
    def static multiply(def value) {
        return value * 3 //intentionally wrong.
    }
}

Suppose we have some existing code using the library:

def result = new MultiplyTwo().multiply(2)

Now suppose that, after using this library throughout your codebase, we discover that it doesn’t give correct results. How can we fix it in one place, outside of the original class, without changing all the code that’s using it? Groovy has an elegant solution to this problem.

With a simple import aliasing, we can fix the bug like this:

import thirdpartylib.MultiplyTwo as OrigMultiplyTwo

class MultiplyTwo extends OrigMultiplyTwo {
    def multiply(def value) {
        return value * 2 // fixed here
    }
}

// nothing to change below here
def multiplylib = new MultiplyTwo()

// assert passes as well
assert 4 == new MultiplyTwo().multiply(2)

Thats it! Notice how Groovy allowed us to use the as keyword to rename our imported class and solve this common problem.

Type aliasing is also useful to solve name collision problems which can occur with * imports.

1.3.3. Scripts versus classes

public static void main vs script

Groovy supports both scripts and classes. Take the following code for example:

Main.groovy
class Main {                                    (1)
    static void main(String... args) {          (2)
        println 'Groovy world!'                 (3)
    }
}
1 define a Main class, the name is arbitrary
2 the public static void main(String[]) method is usable as the main method of the class
3 the main body of the method

This is typical code that you would find coming from Java, where code has to be embedded into a class to be executable. Groovy makes it easier, the following code is equivalent:

Main.groovy
println 'Groovy world!'

A script can be considered as a class without needing to declare it, with some differences.

Script class

A script is always compiled into a class. The Groovy compiler will compile the class for you, with the body of the script copied into a run method. The previous example is therefore compiled as if it was the following:

Main.groovy
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {                     (1)
    def run() {                                 (2)
        println 'Groovy world!'                 (3)
    }
    static void main(String[] args) {           (4)
        InvokerHelper.runScript(Main, args)     (5)
    }
}
1 The Main class extends the groovy.lang.Script class
2 groovy.lang.Script requires a run method returning a value
3 the script body goes into the run method
4 the main method it automatically generated
5 and delegates the execution of the script on the run method

If the script is in a file, then the base name of the file is used to determine the name of the generated script class. In this example, if the name of the file is Main.groovy, then the script class is going to be Main.

Methods

It is possible to define methods into a script, as illustrated here:

int fib(int n) {
    n<2?1:fib(n-1)+fib(n-2)
}
assert fib(10)==89

You can also mix methods and code. The generated script class will carry all methods into the script class, and assemble all script bodies into the run method:

println 'Hello'                                 (1)

int power(int n) { 2**n }                       (2)

println "2^6==${power(6)}"                      (3)
1 script begins
2 a method is defined within the script body
3 and script continues

This code is internally converted into:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
    int power(int n) { 2** n}                   (1)
    def run() {
        println 'Hello'                         (2)
        println "2^6==${power(6)}"              (3)
    }
    static void main(String[] args) {
        InvokerHelper.runScript(Main, args)
    }
}
1 the power method is copied as is into the generated script class
2 first statement is copied into the run method
3 second statement is copied into the run method
Even if Groovy creates a class from your script, it is totally transparent for the user. In particular, scripts are compiled to bytecode, and line numbers are preserved. This implies that if an exception is thrown in a script, the stack trace will show line numbers corresponding to the original script, not the generated code that we have shown.
Variables

Variables in a script do not require a type definition. This means that this script:

int x = 1
int y = 2
assert x+y == 3

will behave the same as:

x = 1
y = 2
assert x+y == 3

However there is a semantic difference between the two:

  • if the variable is declared as in the first example, it is a local variable. It will be declared in the run method that the compiler will generate and will not be visible outside of the script main body. In particular, such a variable will not be visible in other methods of the script

  • if the variable is undeclared, it goes into the script binding. The binding is visible from the methods, and is especially important if you use a script to interact with an application and need to share data between the script and the application. Readers might refer to the integration guide for more information.

If you want a variable to become a field of the class without going into the Binding, you can use the @Field annotation.

1.4. Object orientation

This chapter covers the object orientation of the Groovy programming language.

1.4.1. Types

Primitive types

Groovy supports the same primitive types as those defined by the Java Language Specification:

  • integral types: byte (8 bit), short (16 bit), int (32 bit) and long (64 bit)

  • floating-point types: float (32 bit) and double (64 bit)

  • boolean type (exactly true or false)

  • char type (16 bit, usable as a numeric type, representing an UTF-16 code)

Class

Groovy classes are very similar to Java classes, being compatible to those ones at JVM level. They may have methods and fields/properties, which can have the same modifiers (public, protected, private, static, etc) as Java classes.

Here are key aspects of Groovy classes, that are different from their Java counterparts:

  • Public fields are turned into properties automatically, which results in less verbose code, without so many getter and setter methods. More on this aspect will be covered in the fields and properties section.

  • Their declarations and any property or method without an access modifier are public.

  • Classes do not need to have the same name of the files where they are defined.

  • One file may contain one or more classes (but if a file contains no classes, it is considered a script).

The following code presents an example class.

class Person {                       (1)

    String name                      (2)
    Integer age

    def increaseAge(Integer years) { (3)
        this.age += years
    }
}
1 class beginning, with the name Person
2 string field and property named name
3 method definition
Normal class

Normal classes refer to classes which are top level and concrete. This means they can be instantiated without restrictions from any other classes or scripts. This way, they can only be public (even though the public keyword may be suppressed). Classes are instantiated by calling their constructors, using the new keyword, as in the following snippet.

def p = new Person()
Inner class

Inner classes are defined within another classes. The enclosing class can use the inner class as usual. On the other side, a inner class can access members of its enclosing class, even if they are private. Classes other than the enclosing class are not allowed to access inner classes. Here is an example:

class Outer {
    private String privateStr

    def callInnerMethod() {
        new Inner().methodA()       (1)
    }

    class Inner {                   (2)
        def methodA() {
            println "${privateStr}." (3)
        }
    }
}
1 the inner class is instantiated and its method gets called
2 inner class definition, inside its enclosing class
3 even being private, a field of the enclosing class is accessed by the inner class

There are some reasons for using inner classes:

  • They increase encapsulation by hiding the inner class from other classes, which do not need to know about it. This also leads to cleaner packages and workspaces.

  • They provide a good organization, by grouping classes that are used by only one class.

  • They lead to more maintainable codes, since inner classes are near the classes that use them.

In several cases, inner classes are implementation of interfaces whose methods are needed by the outer class. The code below illustrates this with the usage of threads, which are very common.

class Outer2 {
    private String privateStr = 'some string'

    def startThread() {
       new Thread(new Inner2()).start()
    }

    class Inner2 implements Runnable {
        void run() {
            println "${privateStr}."
        }
    }
}

Note that the class Inner2 is defined only to provide an implementation of the method run to class Outer2. Anonymous inner classes help to eliminate verbosity in this case.

Anonymous inner class

The last example of inner class can be simplified with an anonymous inner class. The same functionality can be achieved with the following code.

class Outer3 {
    private String privateStr = 'some string'

    def startThread() {
        new Thread(new Runnable() {      (1)
            void run() {
                println "${privateStr}."
            }
        }).start()                       (2)
    }
}
1 comparing with the last example of previous section, the new Inner2() was replaced by new Runnable() along with all its implementation
2 the method start is invoked normally

Thus, there was no need to define a new class to be used just once.

Abstract class

Abstract classes represent generic concepts, thus, they cannot be instantiated, being created to be subclassed. Their members include fields/properties and abstract or concrete methods. Abstract methods do not have implementation, and must be implemented by concrete subclasses.

abstract class Abstract {         (1)
    String name

    abstract def abstractMethod() (2)

    def concreteMethod() {
        println 'concrete'
    }
}
1 abstract classes must be declared with abstract keyword
2 abstract methods must also be declared with abstract keyword

Abstract classes are commonly compared to interfaces. But there are at least two important differences of choosing one or another. First, while abstract classes may contain fields/properties and concrete methods, interfaces may contain only abstract methods (method signatures). Moreover, one class can implement several interfaces, whereas it can extend just one class, abstract or not.

Interface

An interface defines a contract that a class needs to conform to. An interface only defines a list of methods that need to be implemented, but does not define the methods implementation.

interface Greeter {                                         (1)
    void greet(String name)                                 (2)
}
1 an interface needs to be declared using the interface keyword
2 an interface only defines method signatures

Methods of an interface are always public. It is an error to use protected or private methods in interfaces:

interface Greeter {
    protected void greet(String name)           (1)
}
1 Using protected is a compile-time error

A class implements an interface if it defines the interface in its implements list or if any of its superclasses does:

class SystemGreeter implements Greeter {                    (1)
    void greet(String name) {                               (2)
        println "Hello $name"
    }
}

def greeter = new SystemGreeter()
assert greeter instanceof Greeter                           (3)
1 The SystemGreeter declares the Greeter interface using the implements keyword
2 Then implements the required greet method
3 Any instance of SystemGreeter is also an instance of the Greeter interface

An interface can extend another interface:

interface ExtendedGreeter extends Greeter {                 (1)
    void sayBye(String name)
}
1 the ExtendedGreeter interface extends the Greeter interface using the extends keyword

It is worth noting that for a class to be an instance of an interface, it has to be explicit. For example, the following class defines the greet method as it is declared in the Greeter interface, but does not declare Greeter in its interfaces:

class DefaultGreeter {
    void greet(String name) { println "Hello" }
}

greeter = new DefaultGreeter()
assert !(greeter instanceof Greeter)

In other words, Groovy does not define structural typing. It is however possible to make an instance of an object implement an interface at runtime, using the as coercion operator:

greeter = new DefaultGreeter()                              (1)
coerced = greeter as Greeter                                (2)
assert coerced instanceof Greeter                           (3)
1 create an instance of DefaultGreeter that does not implement the interface
2 coerce the instance into a Greeter at runtime
3 the coerced instance implements the Greeter interface

You can see that there are two distinct objects: one is the source object, a DefaultGreeter instance, which does not implement the interface. The other is an instance of Greeter that delegates to the coerced object.

Groovy interfaces do not support default implementation like Java 8 interfaces. If you are looking for something similar (but not equal), traits are close to interfaces, but allow default implementation as well as other important features described in this manual.
Constructors

Constructors are special methods used to initialize an object with a specific state. As in normal methods, it is possible for a class to declare more than one constructor. In Groovy there are two ways to invoke constructors: with positional parameters or named parameters. The former one is like we invoke Java constructors, while the second way allows one to specify the parameter names when invoking the constructor.

Positional argument constructor

To create an object by using positional argument constructors, the respective class needs to declare each of the constructors it allows being called. A side effect of this is that, once at least one constructor is declared, the class can only be instantiated by getting one of its constructors called. It is worth noting that, in this case, there is no way to create the class with named parameters.

There is three forms of using a declared constructor. The first one is the normal Java way, with the new keyword. The others rely on coercion of lists into the desired types. In this case, it is possible to coerce with the as keyword and by statically typing the variable.

class PersonConstructor {
    String name
    Integer age

    PersonConstructor(name, age) {          (1)
        this.name = name
        this.age = age
    }
}

def person1 = new PersonConstructor('Marie', 1)  (2)
def person2 = ['Marie', 2] as PersonConstructor  (3)
PersonConstructor person3 = ['Marie', 3]         (4)
1 Constructor declaration
2 Constructor invocation, classic Java way
3 Constructor usage, using coercion with as keyword
4 Constructor usage, using coercion in assignment
Named argument constructor

If no constructor is declared, it is possible to create objects by passing parameters in the form of a map (property/value pairs). This can be in handy in cases where one wants to allow several combinations of parameters. Otherwise, by using traditional positional parameters it would be necessary to declare all possible constructors.

class PersonWOConstructor {                                  (1)
    String name
    Integer age
}

def person4 = new PersonWOConstructor()                      (2)
def person5 = new PersonWOConstructor(name: 'Marie')         (3)
def person6 = new PersonWOConstructor(age: 1)                (4)
def person7 = new PersonWOConstructor(name: 'Marie', age: 2) (5)
1 No constructor declared
2 No parameters given in the instantiation
3 name parameter given in the instantiation
4 age parameter given in the instantiation
5 name and age parameters given in the instantiation

It is important to highlight, however, that this approach gives more power to the constructor caller, while imposes a major responsibility to it. Thus, if a restriction is needed, one can just declare one or more constructors, and the instantiation by named parameters will no longer be available.

Methods

Groovy methods are quite similar to other languages. Some peculiarities will be shown in the next subsections.

Method definition

A method is defined with a return type or with the def keyword, to make the return type untyped. A method can also receive any number of arguments, which may not have their types explicitly declared. Java modifiers can be used normally, and if no visibility modifier is provided, the method is public.

Methods in Groovy always return some value. If no return statement is provided, the value evaluated in the last line executed will be returned. For instance, note that none of the following methods uses the return keyword.

def someMethod() { 'method called' }                           (1)
String anotherMethod() { 'another method called' }             (2)
def thirdMethod(param1) { "$param1 passed" }                   (3)
static String fourthMethod(String param1) { "$param1 passed" } (4)
1 Method with no return type declared and no parameter
2 Method with explicit return type and no parameter
3 Method with a parameter with no type defined
4 Static method with a String parameter
Named arguments

Like constructors, normal methods can also be called with named arguments. They need to receive the parameters as a map. In the method body, the values can be accessed as in normal maps (map.key).

def foo(Map args) { "${args.name}: ${args.age}" }
foo(name: 'Marie', age: 1)
Default arguments

Default arguments make parameters optional. If the argument is not supplied, the method assumes a default value.

def foo(String par1, Integer par2 = 1) { [name: par1, age: par2] }
assert foo('Marie').age == 1

Note that no mandatory parameter can be defined after a default parameter is present, only other default parameters.

Varargs

Groovy supports methods with a variable number of arguments. They are defined like this: def foo(p1, …​, pn, T…​ args). Here foo supports n arguments by default, but also an unspecified number of further arguments exceeding n.

def foo(Object... args) { args.length }
assert foo() == 0
assert foo(1) == 1
assert foo(1, 2) == 2

This example defines a method foo, that can take any number of arguments, including no arguments at all. args.length will return the number of arguments given. Groovy allows T[] as a alternative notation to T…​. That means any method with an array as last parameter is seen by Groovy as a method that can take a variable number of arguments.

def foo(Object[] args) { args.length }
assert foo() == 0
assert foo(1) == 1
assert foo(1, 2) == 2

If a method with varargs is called with null as the vararg parameter, then the argument will be null and not an array of length one with null as the only element.

def foo(Object... args) { args }
assert foo(null) == null

If a varargs method is called with an array as an argument, then the argument will be that array instead of an array of length one containing the given array as the only element.

def foo(Object... args) { args }
Integer[] ints = [1, 2]
assert foo(ints) == [1, 2]

Another important point are varargs in combination with method overloading. In case of method overloading Groovy will select the most specific method. For example if a method foo takes a varargs argument of type T and another method foo also takes one argument of type T, the second method is preferred.

def foo(Object... args) { 1 }
def foo(Object x) { 2 }
assert foo() == 1
assert foo(1) == 2
assert foo(1, 2) == 1
Method selection algorithm

(TBD)

Exception declaration

(TBD)

Fields and properties
Fields

A field is a member of a class or a trait which:

  • a mandatory access modifier (public, protected, or private)

  • one or more optional modifiers (static, final, synchronized)

  • an optional type

  • a mandatory name

class Data {
    private int id                                  (1)
    protected String description                    (2)
    public static final boolean DEBUG = false       (3)
}
1 a private field named id, of type int
2 a protected field named description, of type String
3 a public static final field named DEBUG of type boolean

A field may be initialized directly at declaration:

class Data {
    private String id = IDGenerator.next() (1)
    // ...
}
1 the private field id is initialized with IDGenerator.next()

It is possible to omit the type declaration of a field. This is however considered a bad practice and in general it is a good idea to use strong typing for fields:

class BadPractice {
    private mapping                         (1)
}
class GoodPractice {
    private Map<String,String> mapping      (2)
}
1 the field mapping doesn’t declare a type
2 the field mapping has a strong type

The difference between the two is important if you want to use optional type checking later. It is also important for documentation. However in some cases like scripting or if you want to rely on duck typing it may be interesting to omit the type.

Properties

A property is a combination of a private field and getters/setters. You can define a property with:

  • an absent access modifier (no public, protected or final)

  • one or more optional modifiers (static, final, synchronized)

  • an optional type

  • a mandatory name

Groovy will then generate the getters/setters appropriately. For example:

class Person {
    String name                             (1)
    int age                                 (2)
}
1 creates a backing private String name field, a getName and a setName method
2 creates a backing private int age field, a getAge and a setAge method

If a property is declared final, no setter is generated:

class Person {
    final String name                   (1)
    final int age                       (2)
    Person(String name, int age) {
        this.name = name                (3)
        this.age = age                  (4)
    }
}
1 defines a read-only property of type String
2 defines a read-only property of type int
3 assigns the name parameter to the name field
4 assigns the age parameter to the age field

Properties are accessed by name and will call the getter or setter transparently, unless the code is in the class which defines the property:

class Person {
    String name
    void name(String name) {
        this.name = "Wonder$name"       (1)
    }
    String wonder() {
        this.name                       (2)
    }
}
def p = new Person()
p.name = 'Marge'                        (3)
assert p.name == 'Marge'                (4)
p.name('Marge')                         (5)
assert p.wonder() == 'WonderMarge'      (6)
1 this.name will directly access the field because the property is accessed from within the class that defines it
2 similarily a read access is done directly on the name field
3 write access to the property is done outside of the Person class so it will implicitly call setName
4 read access to the property is done outside of the Person class so it will implicitly call getName
5 this will call the name method on Person which performs a direct access to the field
6 this will call the wonder method on Person which performs a direct read access to the field

It is worth noting that this behavior of accessing the backing field directly is done in order to prevent a stack overflow when using the property access syntax within a class that defines the property.

It is possible to list the properties of a class thanks to the meta properties field of an instance:

class Person {
    String name
    int age
}
def p = new Person()
assert p.properties.keySet().containsAll(['name','age'])

By convention, Groovy will recognize properties even if there is no backing field, if there are getters or setters that follow the Java Beans specification. For example:

class PseudoProperties {
    // a pseudo property "name"
    void setName(String name) {}
    String getName() {}

    // a pseudo read-only property "age"
    int getAge() { 42 }

    // a pseudo write-only property "groovy"
    void setGroovy(boolean groovy) {  }
}
def p = new PseudoProperties()
p.name = 'Foo'                      (1)
assert p.age == 42                  (2)
p.groovy = true                     (3)
1 reading p.name is allowed because there is a pseudo-property name
2 reading p.age is allowed because there is a pseudo-readonly property age
3 writing p.groovy is allowed because there is a pseudo-writeonly property groovy

This syntactic sugar is at the core of many DSLs written in Groovy.

Annotation
Annotation definition

An annotation is a kind of special interface dedicated at annotating elements of the code. An annotation is a type which superinterface is the Annotation interface. Annotations are declared in a very similar way to interfaces, using the @interface keyword:

@interface SomeAnnotation {}

An annotation may define members in the form of methods without bodies and an optional default value. The possible member types are limited to:

For example:

@interface SomeAnnotation {
    String value()                          (1)
}
@interface SomeAnnotation {
    String value() default 'something'      (2)
}
@interface SomeAnnotation {
    int step()                              (3)
}
@interface SomeAnnotation {
    Class appliesTo()                       (4)
}
@interface SomeAnnotation {}
@interface SomeAnnotations {
    SomeAnnotation[] value()                (5)
}
enum DayOfWeek { mon, tue, wed, thu, fri, sat, sun }
@interface Scheduled {
    DayOfWeek dayOfWeek()                   (6)
}
1 an annotation defining a value member of type String
2 an annotation defining a value member of type String with a default value of something
3 an annotation defining a step member of type the primitive type int
4 an annotation defining a appliesTo member of type Class
5 an annotation defining a value member which type is an array of another annotation type
6 an annotation defining a dayOfWeek member which type is the enumeration type DayOfWeek

Unlike in the Java language, in Groovy, an annotation can be used to alter the semantics of the language. It is especially true of AST transformations which will generate code based on annotations.

Annotation placement

An annotation can be applied on various elements of the code:

@SomeAnnotation                 (1)
void someMethod() {
    // ...
}

@SomeAnnotation                 (2)
class SomeClass {}

@SomeAnnotation String var      (3)
1 @SomeAnnotation applies to the someMethod method
2 @SomeAnnotation applies to the SomeClass class
3 @SomeAnnotation applies to the var variable

In order to limit the scope where an annotation can be applied, it is necessary to declare it on the annotation definition, using the Target annotation. For example, here is how you would declare that an annotation can be applied to a class or a method:

import java.lang.annotation.ElementType
import java.lang.annotation.Target

@Target([ElementType.METHOD, ElementType.TYPE])     (1)
@interface SomeAnnotation {}                        (2)
1 the @Target annotation is meant to annotate an annotation with a scope.
2 @SomeAnnotation will therefore only be allowed on TYPE or METHOD

The list of possible targets is available in the ElementType enumeration.

Groovy does not support the TYPE_PARAMETER and TYPE_USE element types which were introduced in Java 8.
Annotation member values

When an annotation is used, it is required to set at least all members that do not have a default value. For example:

@interface Page {
    int statusCode()
}

@Page(statusCode=404)
void notFound() {
    // ...
}

However it is possible to omit value= in the declaration of the value of an annotation if the member value is the only one being set:

@interface Page {
    String value()
    int statusCode() default 200
}

@Page(value='/home')                    (1)
void home() {
    // ...
}

@Page('/users')                         (2)
void userList() {
    // ...
}

@Page(value='error',statusCode=404)     (3)
void notFound() {
    // ...
}
1 we can omit the statusCode because it has a default value, but value needs to be set
2 since value is the only mandatory member without a default, we can omit value=
3 if both value and statusCode need to be set, it is required to use value= for the default value member
Retention policy

The visibility of an annotation depends on its retention policy. The retention policy of an annotation is set using the Retention annotation:

import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

@Retention(RetentionPolicy.SOURCE)                   (1)
@interface SomeAnnotation {}                         (2)
1 the @Retention annotation annotates the @SomeAnnotation annotation
2 so @SomeAnnotation will have a SOURCE retention

The list of possible retention targets and description is available in the RetentionPolicy enumeration. The choice usually depends on whether you want an annotation to be visible at compile time or runtime.

Closure annotation parameters

An interesting feature of annotations in Groovy is that you can use a closure as an annotation value. Therefore annotations may be used with a wide variety of expressions and still have IDE support. For example, imagine a framework where you want to execute some methods based on environmental constraints like the JDK version or the OS. One could write the following code:

class Tasks {
    Set result = []
    void alwaysExecuted() {
        result << 1
    }
    @OnlyIf({ jdk>=6 })
    void supportedOnlyInJDK6() {
        result << 'JDK 6'
    }
    @OnlyIf({ jdk>=7 && windows })
    void requiresJDK7AndWindows() {
        result << 'JDK 7 Windows'
    }
}

For the @OnlyIf annotation to accept a Closure as an argument, you only have to declare the value as a Class:

@Retention(RetentionPolicy.RUNTIME)
@interface OnlyIf {
    Class value()                    (1)
}

To complete the example, let’s write a sample runner that would use that information:

class Runner {
    static <T> T run(Class<T> taskClass) {
        def tasks = taskClass.newInstance()                                         (1)
        def params = [jdk:6, windows: false]                                        (2)
        tasks.class.declaredMethods.each { m ->                                     (3)
            if (Modifier.isPublic(m.modifiers) && m.parameterTypes.length == 0) {   (4)
                def onlyIf = m.getAnnotation(OnlyIf)                                (5)
                if (onlyIf) {
                    Closure cl = onlyIf.value().newInstance(tasks,tasks)            (6)
                    cl.delegate = params                                            (7)
                    if (cl()) {                                                     (8)
                        m.invoke(tasks)                                             (9)
                    }
                } else {
                    m.invoke(tasks)                                                 (10)
                }
            }
        }
        tasks                                                                       (11)
    }
}
1 create a new instance of the class passed as an argument (the task class)
2 emulate an environment which is JDK 6 and not Windows
3 iterate on all declared methods of the task class
4 if the method is public and takes no-argument
5 try to find the @OnlyIf annotation
6 if it is found get the value and create a new Closure out of it
7 set the delegate of the closure to our environment variable
8 call the closure, which is the annotation closure. It will return a boolean
9 if it is true, call the method
10 if the method is not annotated with @OnlyIf, execute the method anyway
11 after that, return the task object

Then the runner can be used this way:

def tasks = Runner.run(Tasks)
assert tasks.result == [1, 'JDK 6'] as Set
Meta-annotations
Declaring meta-annotations

Meta-annotations, also known as annotation aliases are annotations that are replaced at compile time by other annotations (one meta-annotation is an alias for one or more annotations). Meta-annotations can be used to reduce the size of code involving multiple annotations.

Let’s start with a simple example. Imagine you have the @Service and @Transactional annotations and that you want to annotate a class with both:

@Service
@Transactional
class MyTransactionalService {}

Given the multiplication of annotations that you could add to the same class, a meta-annotation could help by reducing the two annotations with a single one having the very same semantics. For example, we might want to write this instead:

@TransactionalService                           (1)
class MyTransactionalService {}
1 @TransactionalService is a meta-annotation

A meta-annotation is declared as a regular annotation but annotated with @AnnotationCollector and the list of annotations it is collecting. In our case, the @TransactionalService annotation can be written:

import groovy.transform.AnnotationCollector

@Service                                        (1)
@Transactional                                  (2)
@AnnotationCollector                            (3)
@interface TransactionalService {
}
1 annotate the meta-annotation with @Service
2 annotate the meta-annotation with @Transactional
3 annotate the meta-annotation with @AnnotationCollector
Behavior of meta-annotations

Groovy supports both precompiled and source form meta-annotations. This means that your meta-annotation may be precompiled, or you can have it in the same source tree as the one you are currently compiling.

INFO: Meta-annotations are a Groovy feature only. There is no chance for you to annotate a Java class with a meta-annotation and hope it will do the same as in Groovy. Likewise, you cannot write a meta-annotation in Java: both the meta-annotation definition and usage have to be Groovy code.

When the Groovy compiler encounters a class annotated with a meta-annotation, it replaces it with the collected annotations. That is, in our previous example, that it will replace @TransactionalService with @Transactional and @Service:

def annotations = MyTransactionalService.annotations*.annotationType()
assert (Service in annotations)
assert (Transactional in annotations)

The conversion from a meta-annotation to the collected annotations is performed during the semantic analysis compilation phase. 

In addition to replacing the alias with the collected annotations, a meta-annotation is capable of processing them, including arguments.

Meta-annotation parameters

Meta-annotations can collect annotations which have parameters. To illustrate this, we will imagine two annotations, each of them accepting one argument:

@Timeout(after=3600)
@Dangerous(type='explosive')

And that you want create a meta-annotation named @Explosive:

@Timeout(after=3600)
@Dangerous(type='explosive')
@AnnotationCollector
public @interface Explosive {}

By default, when the annotations are replaced, they will get the values as they were defined in the alias. More interesting, the meta-annotation supports overriding specific values:

@Explosive(after=0)                 (1)
class Bomb {}
1 the after value provided as a parameter to @Explosive overrides the one defined in the @Timeout annotation

If two annotations define the same parameter name, the default processor will copy the annotation value to all annotations that accept this parameter:

@Retention(RetentionPolicy.RUNTIME)
public @interface Foo {
   String value()                                   (1)
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Bar {
    String value()                                  (2)
}

@Foo
@Bar
@AnnotationCollector
public @interface FooBar {}                         (3)

@Foo('a')
@Bar('b')
class Bob {}                                        (4)

assert Bob.getAnnotation(Foo).value() == 'a'        (5)
println Bob.getAnnotation(Bar).value() == 'b'       (6)

@FooBar('a')
class Joe {}                                        (7)
assert Joe.getAnnotation(Foo).value() == 'a'        (8)
println Joe.getAnnotation(Bar).value() == 'a'       (9)
1 the @Foo annotation defines the value member of type String
2 the @Bar annotation also defines the value member of type String
3 the @FooBar meta-annotation aggregates @Foo and @Bar
4 class Bob is annotated with @Foo and @Bar
5 the value of the @Foo annotation on Bob is a
6 while the value of the @Bar annotation on Bob is b
7 class Joe is annotated with @FooBar
8 then the value of the @Foo annotation on Joe is a
9 and the value of the @Bar annotation on Joe is also a

In the second case, the meta-annotation value was copied in both @Foo and @Bar annotations.

It is a compile time error if the collected annotations define the same members with incompatible types. For example if on the previous example @Foo defined a value of type String but @Bar defined a value of type int.

It is however possible to customize the behavior of meta-annotations and describe how collected annotations are expanded.

Custom annotation processors

A custom annotation processor will let you choose how to expand a meta-annotation into collected annotations. The behaviour of the meta-annotation is, in this case, totally up to you. To do this, you must:

  • create a meta-annotation processor, extending AnnotationCollectorTransform

  • declare the processor to be used in the meta-annotation declaration

To illustrate this, we are going to explore how the meta-annotation @CompileDynamic is implemented.

@CompileDynamic is a meta-annotation that expands itself to @CompileStatic(TypeCheckingMode.SKIP). The problem is that the default meta annotation processor doesn’t support enums and the annotation value TypeCheckingMode.SKIP is one.

The naive implementation here would not work:

@CompileStatic(TypeCheckingMode.SKIP)
@AnnotationCollector
public @interface CompileDynamic {}

Instead, we will define it like this:

@AnnotationCollector(processor = "org.codehaus.groovy.transform.CompileDynamicProcessor")
public @interface CompileDynamic {
}

The first thing you may notice is that our interface is no longer annotated with @CompileStatic. The reason for this is that we rely on the processor parameter instead, that references a class which will generate the annotation.

Here is how the custom processor is implemented:

CompileDynamicProcessor.groovy
@CompileStatic                                                                  (1)
class CompileDynamicProcessor extends AnnotationCollectorTransform {            (2)
    private static final ClassNode CS_NODE = ClassHelper.make(CompileStatic)    (3)
    private static final ClassNode TC_NODE = ClassHelper.make(TypeCheckingMode) (4)

    List<AnnotationNode> visit(AnnotationNode collector,                        (5)
                               AnnotationNode aliasAnnotationUsage,             (6)
                               AnnotatedNode aliasAnnotated,                    (7)
                               SourceUnit source) {                             (8)
        def node = new AnnotationNode(CS_NODE)                                  (9)
        def enumRef = new PropertyExpression(
            new ClassExpression(TC_NODE), "SKIP")                               (10)
        node.addMember("value", enumRef)                                        (11)
        Collections.singletonList(node)                                         (12)
    }
}
1 our custom processor is written in Groovy, and for better compilation performance, we use static compilation
2 the custom processor has to extend AnnotationCollectorTransform
3 create a class node representing the @CompileStatic annotation type
4 create a class node representing the TypeCheckingMode enum type
5 collector is the @AnnotationCollector node found in the meta-annotation. Usually unused.
6 aliasAnnotationUsage is the meta-annotation being expanded, here it is @CompileDynamic
7 aliasAnnotated is the node being annotated with the meta-annotation
8 sourceUnit is the SourceUnit being compiled
9 we create a new annotation node for @CompileStatic
10 we create an expression equivalent to TypeCheckingMode.SKIP
11 we add that expression to the annotation node, which is now @CompileStatic(TypeCheckingMode.SKIP)
12 return the generated annotation

In the example, the visit method is the only method which has to be overriden. It is meant to return a list of annotation nodes that will be added to the node annotated with the meta-annotation. In this example, we return a single one corresponding to @CompileStatic(TypeCheckingMode.SKIP).

Inheritance

(TBD)

Generics

(TBD)

1.4.2. Traits

Traits are a a structural construct of the language which allow:

  • composition of behaviors

  • runtime implementation of interfaces

  • behavior overriding

  • compatibility with static type checking/compilation

They can be seen as interfaces carrying both default implementations and state. A trait is defined using the trait keyword:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
1 declaration of a trait
2 declaration of a method inside a trait

Then it can be used like a normal interface using the implements keyword:

class Bird implements FlyingAbility {}          (1)
def b = new Bird()                              (2)
assert b.fly() == "I'm flying!"                 (3)
1 Adds the trait FlyingAbility to the Bird class capabilities
2 instantiate a new Bird
3 the Bird class automatically gets the behavior of the FlyingAbility trait

Traits allow a wide range of capabilities, from simple composition to testing, which are described thoroughly in this section.

Methods
Public methods

Declaring a method in a trait can be done like any regular method in a class:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
1 declaration of a trait
2 declaration of a method inside a trait
Abstract methods

In addition, traits may declare abstract methods too, which therefore need to be implemented in the class implementing the trait:

trait Greetable {
    abstract String name()                              (1)
    String greeting() { "Hello, ${name()}!" }           (2)
}
1 implementing class will have to declare the name method
2 can be mixed with a concrete method

Then the trait can be used like this:

class Person implements Greetable {                     (1)
    String name() { 'Bob' }                             (2)
}

def p = new Person()
assert p.greeting() == 'Hello, Bob!'                    (3)
1 implement the trait Greetable
2 since name was abstract, it is required to implement it
3 then greeting can be called
Private methods

Traits may also define private methods. Those methods will not appear in the trait contract interface:

trait Greeter {
    private String greetingMessage() {                      (1)
        'Hello from a private method!'
    }
    String greet() {
        def m = greetingMessage()                           (2)
        println m
        m
    }
}
class GreetingMachine implements Greeter {}                 (3)
def g = new GreetingMachine()
assert g.greet() == "Hello from a private method!"          (4)
try {
    assert g.greetingMessage()                              (5)
} catch (MissingMethodException e) {
    println "greetingMessage is private in trait"
}
1 define a private method greetingMessage in the trait
2 the public greet message calls greetingMessage by default
3 create a class implementing the trait
4 greet can be called
5 but not greetingMessage
Traits only support public and private methods. Neither protected nor package private scopes are supported.
The meaning of this

this represents the implementing instance. Think of a trait as a superclass. This means that when you write:

trait Introspector {
    def whoAmI() { this }
}
class Foo implements Introspector {}
def foo = new Foo()

then calling:

foo.whoAmI()

will return the same instance:

assert foo.whoAmI().is(foo)
Interfaces

Traits may implement interfaces, in which case the interfaces are declared using the implements keyword:

interface Named {                                       (1)
    String name()
}
trait Greetable implements Named {                      (2)
    String greeting() { "Hello, ${name()}!" }
}
class Person implements Greetable {                     (3)
    String name() { 'Bob' }                             (4)
}

def p = new Person()
assert p.greeting() == 'Hello, Bob!'                    (5)
assert p instanceof Named                               (6)
assert p instanceof Greetable                           (7)
1 declaration of a normal interface
2 add Named to the list of implemented interfaces
3 declare a class that implements the Greetable trait
4 implement the missing greet method
5 the greeting implementation comes from the trait
6 make sure Person implements the Named interface
7 make sure Person implements the Greetable trait
Properties

A trait may define properties, like in the following example:

trait Named {
    String name                             (1)
}
class Person implements Named {}            (2)
def p = new Person(name: 'Bob')             (3)
assert p.name == 'Bob'                      (4)
assert p.getName() == 'Bob'                 (5)
1 declare a property name inside a trait
2 declare a class which implements the trait
3 the property is automatically made visible
4 it can be accessed using the regular property accessor
5 or using the regular getter syntax
Fields
Private fields

Since traits allow the use of private methods, it can also be interesting to use private fields to store state. Traits will let you do that:

trait Counter {
    private int count = 0                   (1)
    int count() { count += 1; count }       (2)
}
class Foo implements Counter {}             (3)
def f = new Foo()
assert f.count() == 1                       (4)
assert f.count() == 2
1 declare a private field count inside a trait
2 declare a public method count that increments the counter and returns it
3 declare a class that implements the Counter trait
4 the count method can use the private field to keep state
This is a major difference with Java 8 virtual extension methods. While virtual extension methods do not carry state, traits can. Moreover, traits in Groovy are supported starting with Java 6, because their implementation does not rely on virtual extension methods. This means that even if a trait can be seen from a Java class as a regular interface, that interface will not have default methods, only abstract ones.
Public fields

Public fields work the same way as private fields, but in order to avoid the diamond problem, field names are remapped in the implementing class:

trait Named {
    public String name                      (1)
}
class Person implements Named {}            (2)
def p = new Person()                        (3)
p.Named__name = 'Bob'                       (4)
1 declare a public field inside the trait
2 declare a class implementing the trait
3 create an instance of that class
4 the public field is available, but renamed

The name of the field depends on the fully qualified name of the trait. All dots (.) in package are replaced with an underscore (_), and the final name includes a double underscore. So if the type of the field is String, the name of the package is my.package, the name of the trait is Foo and the name of the field is bar, in the implementing class, the public field will appear as:

String my_package_Foo__bar
While traits support public fields, it is not recommended to use them and considered as a bad practice.
Composition of behaviors

Traits can be used to implement multiple inheritance in a controlled way, avoiding the diamond issue. For example, we can have the following traits:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
trait SpeakingAbility {
    String speak() { "I'm speaking!" }
}

And a class implementing both traits:

class Duck implements FlyingAbility, SpeakingAbility {} (1)

def d = new Duck()                                      (2)
assert d.fly() == "I'm flying!"                         (3)
assert d.speak() == "I'm speaking!"                     (4)
1 the Duck class implements both FlyingAbility and SpeakingAbility
2 creates a new instance of Duck
3 we can call the method fly from FlyingAbility
4 but also the method speak from SpeakingAbility

Traits encourage the reuse of capabilities among objects, and the creation of new classes by the composition of existing behavior.

Overriding default methods

Traits provide default implementations for methods, but it is possible to override them in the implementing class. For example, we can slightly change the example above, by having a duck which quacks:

class Duck implements FlyingAbility, SpeakingAbility {
    String quack() { "Quack!" }                         (1)
    String speak() { quack() }                          (2)
}

def d = new Duck()
assert d.fly() == "I'm flying!"                         (3)
assert d.quack() == "Quack!"                            (4)
assert d.speak() == "Quack!"                            (5)
1 define a method specific to Duck, named quack
2 override the default implementation of speak so that we use quack instead
3 the duck is still flying, from the default implementation
4 quack comes from the Duck class
5 speak no longer uses the default implementation from SpeakingAbility
Extending traits
Simple inheritance

Traits may extend another trait, in which case you must use the extends keyword:

trait Named {
    String name                                     (1)
}
trait Polite extends Named {                        (2)
    String introduce() { "Hello, I am $name" }      (3)
}
class Person implements Polite {}
def p = new Person(name: 'Alice')                   (4)
assert p.introduce() == 'Hello, I am Alice'         (5)
1 the Named trait defines a single name property
2 the Polite trait extends the Named trait
3 Polite adds a new method which has access to the name property of the super-trait
4 the name property is visible from the Person class implementing Polite
5 as is the introduce method
Multiple inheritance

Alternatively, a trait may extend multiple traits. In that case, all super traits must be declared in the implements clause:

trait WithId {                                      (1)
    Long id
}
trait WithName {                                    (2)
    String name
}
trait Identified implements WithId, WithName {}     (3)
1 WithId trait defines the id property
2 WithName trait defines the name property
3 Identified is a trait which inherits both WithId and WithName
Duck typing and traits
Dynamic code

Traits can call any dynamic code, like a normal Groovy class. This means that you can, in the body of a method, call methods which are supposed to exist in an implementing class, without having to explicitly declare them in an interface. This means that traits are fully compatible with duck typing:

trait SpeakingDuck {
    String speak() { quack() }                      (1)
}
class Duck implements SpeakingDuck {
    String methodMissing(String name, args) {
        "${name.capitalize()}!"                     (2)
    }
}
def d = new Duck()
assert d.speak() == 'Quack!'                        (3)
1 the SpeakingDuck expects the quack method to be defined
2 the Duck class does implement the method using methodMissing
3 calling the speak method triggers a call to quack which is handled by methodMissing
Dynamic methods in a trait

It is also possible for a trait to implement MOP methods like methodMissing or propertyMissing, in which case implementing classes will inherit the behavior from the trait, like in this example:

trait DynamicObject {                               (1)
    private Map props = [:]
    def methodMissing(String name, args) {
        name.toUpperCase()
    }
    def propertyMissing(String prop) {
        props[prop]
    }
    void setProperty(String prop, Object value) {
        props[prop] = value
    }
}

class Dynamic implements DynamicObject {
    String existingProperty = 'ok'                  (2)
    String existingMethod() { 'ok' }                (3)
}
def d = new Dynamic()
assert d.existingProperty == 'ok'                   (4)
assert d.foo == null                                (5)
d.foo = 'bar'                                       (6)
assert d.foo == 'bar'                               (7)
assert d.existingMethod() == 'ok'                   (8)
assert d.someMethod() == 'SOMEMETHOD'               (9)
1 create a trait implementing several MOP methods
2 the Dynamic class defines a property
3 the Dynamic class defines a method
4 calling an existing property will call the method from Dynamic
5 calling an non-existing property will call the method from the trait
6 will call setProperty defined on the trait
7 will call getProperty defined on the trait
8 calling an existing method on Dynamic
9 but calling a non existing method thanks to the trait methodMissing
Multiple inheritance conflicts
Default conflict resolution

It is possible for a class to implement multiple traits. If some trait defines a method with the same signature as a method in another trait, we have a conflict:

trait A {
    String exec() { 'A' }               (1)
}
trait B {
    String exec() { 'B' }               (2)
}
class C implements A,B {}               (3)
1 trait A defines a method named exec returning a String
2 trait B defines the very same method
3 class C implements both traits

In this case, the default behavior is that methods from the last declared trait wins. Here, B is declared after A so the method from B will be picked up:

def c = new C()
assert c.exec() == 'B'
User conflict resolution

In case this behavior is not the one you want, you can explicitly choose which method to call using the Trait.super.foo syntax. In the example above, we can force to choose the method from trait A, by writing this:

class C implements A,B {
    String exec() { A.super.exec() }    (1)
}
def c = new C()
assert c.exec() == 'A'                  (2)
1 explicit call of exec from the trait A
2 calls the version from A instead of using the default resolution, which would be the one from B
Runtime implementation of traits
Implementing a trait at runtime

Groovy also supports implementing traits dynamically at runtime. It allows you to "decorate" an existing object using a trait. As an example, let’s start with this trait and the following class:

trait Extra {
    String extra() { "I'm an extra method" }            (1)
}
class Something {                                       (2)
    String doSomething() { 'Something' }                (3)
}
1 the Extra trait defines an extra method
2 the Something class does not implement the Extra trait
3 Something only defines a method doSomething

Then if we do:

def s = new Something()
s.extra()

the call to extra would fail because Something is not implementing Extra. It is possible to do it at runtime with the following syntax:

def s = new Something() as Extra                        (1)
s.extra()                                               (2)
s.doSomething()                                         (3)
1 use of the as keyword to coerce an object to a trait at runtime
2 then extra can be called on the object
3 and doSomething is still callable
When coercing an object to a trait, the result of the operation is not the same instance. It is guaranteed that the coerced object will implement both the trait and the interfaces that the original object implements, but the result will not be an instance of the original class.
Implementing multiple traits at once

Should you need to implement several traits at once, you can use the withTraits method instead of the as keyword:

trait A { void methodFromA() {} }
trait B { void methodFromB() {} }

class C {}

def c = new C()
c.methodFromA()                     (1)
c.methodFromB()                     (2)
def d = c.withTraits A, B           (3)
d.methodFromA()                     (4)
d.methodFromB()                     (5)
1 call to methodFromA will fail because C doesn’t implement A
2 call to methodFromB will fail because C doesn’t implement B
3 withTrait will wrap c into something which implements A and B
4 methodFromA will now pass because d implements A
5 methodFromB will now pass because d also implements B
When coercing an object to multiple traits, the result of the operation is not the same instance. It is guaranteed that the coerced object will implement both the traits and the interfaces that the original object implements, but the result will not be an instance of the original class.
Chaining behavior

Groovy supports the concept of stackable traits. The idea is to delegate from one trait to the other if the current trait is not capable of handling a message. To illustrate this, let’s imagine a message handler interface like this:

interface MessageHandler {
    void on(String message, Map payload)
}

Then you can compose a message handler by applying small behaviors. For example, let’s define a default handler in the form of a trait:

trait DefaultHandler implements MessageHandler {
    void on(String message, Map payload) {
        println "Received $message with payload $payload"
    }
}

Then any class can inherit the behavior of the default handler by implementing the trait:

class SimpleHandler implements DefaultHandler {}

Now what if you want to log all messages, in addition to the default handler? One option is to write this:

class SimpleHandlerWithLogging implements DefaultHandler {
    void on(String message, Map payload) {                                  (1)
        println "Seeing $message with payload $payload"                     (2)
        DefaultHandler.super.on(message, payload)                           (3)
    }
}
1 explicitly implement the on method
2 perform logging
3 continue by delegating to the DefaultHandler trait

This works but this approach has drawbacks:

  1. the logging logic is bound to a "concrete" handler

  2. we have an explicit reference to DefaultHandler in the on method, meaning that if we happen to change the trait that our class implements, code will be broken

As an alternative, we can write another trait which responsibility is limited to logging:

trait LoggingHandler implements MessageHandler {                            (1)
    void on(String message, Map payload) {
        println "Seeing $message with payload $payload"                     (2)
        super.on(message, payload)                                          (3)
    }
}
1 the logging handler is itself a handler
2 prints the message it receives
3 then super makes it delegate the call to the next trait in the chain

Then our class can be rewritten as this:

class HandlerWithLogger implements DefaultHandler, LoggingHandler {}
def loggingHandler = new HandlerWithLogger()
loggingHandler.on('test logging', [:])

which will print:

Seeing test logging with payload [:]
Received test logging with payload [:]

As the priority rules imply that LoggerHandler wins because it is declared last, then a call to on will use the implementation from LoggingHandler. But the latter has a call to super, which means the next trait in the chain. Here, the next trait is DefaultHandler so both will be called:

The interest of this approach becomes more evident if we add a third handler, which is responsible for handling messages that start with say:

trait SayHandler implements MessageHandler {
    void on(String message, Map payload) {
        if (message.startsWith("say")) {                                    (1)
            println "I say ${message - 'say'}!"
        } else {
            super.on(message, payload)                                      (2)
        }
    }
}
1 a handler specific precondition
2 if the precondition is not met, pass the message to the next handler in the chain

Then our final handler looks like this:

class Handler implements DefaultHandler, SayHandler, LoggingHandler {}
def h = new Handler()
h.on('foo', [:])
h.on('sayHello', [:])

Which means:

  • messages will first go through the logging handler

  • the logging handler calls super which will delegate to the next handler, which is the SayHandler

  • if the message starts with say, then the handler consumes the message

  • if not, the say handler delegates to the next handler in the chain

This approach is very powerful because it allows you to write handlers that do not know each other and yet let you combine them in the order you want. For example, if we execute the code, it will print:

Seeing foo with payload [:]
Received foo with payload [:]
Seeing sayHello with payload [:]
I say Hello!

but if we move the logging handler to be the second one in the chain, the output is different:

class AlternateHandler implements DefaultHandler, LoggingHandler, SayHandler {}
h = new AlternateHandler()
h.on('foo', [:])
h.on('sayHello', [:])

prints:

Seeing foo with payload [:]
Received foo with payload [:]
I say Hello!

The reason is that now, since the SayHandler consumes the message without calling super, the logging handler is not called anymore.

Semantics of super inside a trait

If a class implements multiple traits and a call to an unqualified super is found, then:

  1. if the class implements another trait, the call delegates to the next trait in the chain

  2. if there isn’t any trait left in the chain, super refers to the super class of the implementing class (this)

For example, it is possible to decorate final classes thanks to this behavior:

trait Filtering {                                       (1)
    StringBuilder append(String str) {                  (2)
        def subst = str.replace('o','')                 (3)
        super.append(subst)                             (4)
    }
    String toString() { super.toString() }              (5)
}
def sb = new StringBuilder().withTraits Filtering       (6)
sb.append('Groovy')
assert sb.toString() == 'Grvy'                          (7)
1 define a trait named Filtering, supposed to be applied on a StringBuilder at runtime
2 redefine the append method
3 remove all 'o’s from the string
4 then delegate to super
5 in case toString is called, delegate to super.toString
6 runtime implementation of the Filtering trait on a StringBuilder instance
7 the string which has been appended no longer contains the letter o

In this example, when super.append is encountered, there is no other trait implemented by the target object, so the method which is called is the original append method, that is to say the one from StringBuilder. The same trick is used for toString, so that the string representation of the proxy object which is generated delegates to the toString of the StringBuilder instance.

Advanced features
SAM type coercion

If a trait defines a single abstract method, it is candidate for SAM (Single Abstract Method) type coercion. For example, imagine the following trait:

trait Greeter {
    String greet() { "Hello $name" }        (1)
    abstract String getName()               (2)
}
1 the greet method is not abstract and calls the abstract method getName
2 getName is an abstract method

Since getName is the single abstract method in the Greeter trait, you can write:

Greeter greeter = { 'Alice' }               (1)
1 the closure "becomes" the implementation of the getName single abstract method

or even:

void greet(Greeter g) { println g.greet() } (1)
greet { 'Alice' }                           (2)
1 the greet method accepts the SAM type Greeter as parameter
2 we can call it directly with a closure
Differences with Java 8 default methods

In Java 8, interfaces can have default implementations of methods. If a class implements an interface and does not provide an implementation for a default method, then the implementation from the interface is chosen. Traits behave the same but with a major difference: the implementation from the trait is always used if the class declares the trait in its interface list and that it doesn’t provide an implementation.

This feature can be used to compose behaviors in an very precise way, in case you want to override the behavior of an already implemented method.

To illustrate the concept, let’s start with this simple example:

import groovy.transform.CompileStatic
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.customizers.ImportCustomizer

class SomeTest extends GroovyTestCase {
    def config
    def shell

    void setup() {
        config = new CompilerConfiguration()
        shell = new GroovyShell(config)
    }
    void testSomething() {
        assert shell.evaluate('1+1') == 2
    }
    void otherTest() { /* ... */ }
}

In this example, we create a simple test case which uses two properties (config and shell) and uses those in multiple test methods. Now imagine that you want to test the same, but with another distinct compiler configuration. One option is to create a subclass of SomeTest:

class AnotherTest extends SomeTest {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( ... )
        shell = new GroovyShell(config)
    }
}

It works, but what if you have actually multiple test classes, and that you want to test the new configuration for all those test classes? Then you would have to create a distinct subclass for each test class:

class YetAnotherTest extends SomeTest {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( ... )
        shell = new GroovyShell(config)
    }
}

Then what you see is that the setup method of both tests is the same. The idea, then, is to create a trait:

trait MyTestSupport {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( new ASTTransformationCustomizer(CompileStatic) )
        shell = new GroovyShell(config)
    }
}

Then use it in the subclasses:

class AnotherTest extends SomeTest implements MyTestSupport {}
class YetAnotherTest extends SomeTest2 implements MyTestSupport {}
...

It would allow us to dramatically reduce the boilerplate code, and reduces the risk of forgetting to change the setup code in case we decide to change it. Even if setup is already implemented in the super class, since the test class declares the trait in its interface list, the behavior will be borrowed from the trait implementation!

This feature is in particular useful when you don’t have access to the super class source code. It can be used to mock methods or force a particular implementation of a method in a subclass. It lets you refactor your code to keep the overridden logic in a single trait and inherit a new behavior just by implementing it. The alternative, of course, is to override the method in every place you would have used the new code.

It’s worth noting that if you use runtime traits, the methods from the trait are always preferred to those of the proxied object:
class Person {
    String name                                         (1)
}
trait Bob {
    String getName() { 'Bob' }                          (2)
}

def p = new Person(name: 'Alice')
assert p.name == 'Alice'                                (3)
def p2 = p as Bob                                       (4)
assert p2.name == 'Bob'                                 (5)
1 the Person class defines a name property which results in a getName method
2 Bob is a trait which defines getName as returning Bob
3 the default object will return Alice
4 p2 coerces p into Bob at runtime
5 getName returns Bob because getName is taken from the trait
Again, don’t forget that dynamic trait coercion returns a distinct object which only implements the original interfaces, as well as the traits.
Differences with mixins

There are several conceptual differences with mixins, as they are available in Groovy. Note that we are talking about runtime mixins, not the @Mixin annotation which is deprecated in favour of traits.

First of all, methods defined in a trait are visible in bytecode:

  • internally, the trait is represented as an interface (without default methods) and several helper classes

  • this means that an object implementing a trait effectively implements an interface

  • those methods are visible from Java

  • they are compatible with type checking and static compilation

Methods added through a mixin are, on the contrary, only visible at runtime:

class A { String methodFromA() { 'A' } }        (1)
class B { String methodFromB() { 'B' } }        (2)
A.metaClass.mixin B                             (3)
def o = new A()
assert o.methodFromA() == 'A'                   (4)
assert o.methodFromB() == 'B'                   (5)
assert o instanceof A                           (6)
assert !(o instanceof B)                        (7)
1 class A defines methodFromA
2 class B defines methodFromB
3 mixin B into A
4 we can call methodFromA
5 we can also call methodFromB
6 the object is an instance of A
7 but it’s not an instanceof B

The last point is actually a very important and illustrates a place where mixins have an advantage over traits: the instances are not modified, so if you mixin some class into another, there isn’t a third class generated, and methods which respond to A will continue responding to A even if mixed in.

Static methods, properties and fields
The following instructions are subject to caution. Static member support is work in progress and still experimental. The information below is valid for 2.4.4 only.

It is possible to define static methods in a trait, but it comes with numerous limitations:

  • traits with static methods cannot be compiled statically or type checked. All static methods/properties/field are accessed dynamically (it’s a limitation from the JVM).

  • the trait is interpreted as a template for the implementing class, which means that each implementing class will get its own static methods/properties/methods. So a static member declared on a trait doesn’t belong to the Trait, but to it’s implementing class.

Let’s start with a simple example:

trait TestHelper {
    public static boolean CALLED = false        (1)
    static void init() {                        (2)
        CALLED = true                           (3)
    }
}
class Foo implements TestHelper {}
Foo.init()                                      (4)
assert Foo.TestHelper__CALLED                   (5)
1 the static field is declared in the trait
2 a static method is also declared in the trait
3 the static field is updated within the trait
4 a static method init is made available to the implementing class
5 the static field is remapped to avoid the diamond issue

As usual, it is not recommended to use public fields. Anyway, should you want this, you must understand that the following code would fail:

Foo.CALLED = true

because there is no static field CALLED defined on the trait itself. Likewise, if you have two distinct implementing classes, each one gets a distinct static field:

class Bar implements TestHelper {}              (1)
class Baz implements TestHelper {}              (2)
Bar.init()                                      (3)
assert Bar.TestHelper__CALLED                   (4)
assert !Baz.TestHelper__CALLED                  (5)
1 class Bar implements the trait
2 class Baz also implements the trait
3 init is only called on Bar
4 the static field CALLED on Bar is updated
5 but the static field CALLED on Baz is not, because it is distinct
Inheritance of state gotchas

We have seen that traits are stateful. It is possible for a trait to define fields or properties, but when a class implements a trait, it gets those fields/properties on a per-trait basis. So consider the following example:

trait IntCouple {
    int x = 1
    int y = 2
    int sum() { x+y }
}

The trait defines two properties, x and y, as well as a sum method. Now let’s create a class which implements the trait:

class BaseElem implements IntCouple {
    int f() { sum() }
}
def base = new BaseElem()
assert base.f() == 3

The result of calling f is 3, because f delegates to sum in the trait, which has state. But what if we write this instead?

class Elem implements IntCouple {
    int x = 3                                       (1)
    int y = 4                                       (2)
    int f() { sum() }                               (3)
}
def elem = new Elem()
1 Override property x
2 Override property y
3 Call sum from trait

If you call elem.f(), what is the expected output? Actually it is:

assert elem.f() == 3

The reason is that the sum method accesses the fields of the trait. So it is using the x and y values defined in the trait. If you want to use the values from the implementing class, then you need to dereference fields by using getters and setters, like in this last example:

trait IntCouple {
    int x = 1
    int y = 2
    int sum() { getX()+getY() }
}

class Elem implements IntCouple {
    int x = 3
    int y = 4
    int f() { sum() }
}
def elem = new Elem()
assert elem.f() == 7
Self types
Type constraints on traits

Sometimes you will want to write a trait that can only be applied to some type. For example, you may want to apply a trait on a class that extends another class which is beyond your control, and still be able to call those methods. To illustrate this, let’s start with this example:

class CommunicationService {
    static void sendMessage(String from, String to, String message) {       (1)
        println "$from sent [$message] to $to"
    }
}

class Device { String id }                                                  (2)

trait Communicating {
    void sendMessage(Device to, String message) {
        CommunicationService.sendMessage(id, to.id, message)                (3)
    }
}

class MyDevice extends Device implements Communicating {}                   (4)

def bob = new MyDevice(id:'Bob')
def alice = new MyDevice(id:'Alice')
bob.sendMessage(alice,'secret')                                             (5)
1 A Service class, beyond your control (in a library, …​) defines a sendMessage method
2 A Device class, beyond your control (in a library, …​)
3 Defines a communicating trait for devices that can call the service
4 Defines MyDevice as a communicating device
5 The method from the trait is called, and id is resolved

It is clear, here, that the Communicating trait can only apply to Device. However, there’s no explicit contract to tell that, because traits cannot extend classes. However, the code compiles and runs perfectly fine, because id in the trait method will be resolved dynamically. The problem is that there is nothing that prevents the trait from being applied to any class which is not a Device. Any class which has an id would work, while any class that does not have an id property would cause a runtime error.

The problem is even more complex if you want to enable type checking or apply @CompileStatic on the trait: because the trait knows nothing about itself being a Device, the type checker will complain saying that it does not find the id property.

One possibility is to explicitly add a getId method in the trait, but it would not solve all issues. What if a method requires this as a parameter, and actually requires it to be a Device?

class SecurityService {
    static void check(Device d) { if (d.id==null) throw new SecurityException() }
}

If you want to be able to call this in the trait, then you will explicitly need to cast this into a Device. This can quickly become unreadable with explicit casts to this everywhere.

The @SelfType annotation

In order to make this contract explicit, and to make the type checker aware of the type of itself, Groovy provides a @SelfType annotation that will:

  • let you declare the types that a class that implements this trait must inherit or implement

  • throw a compile time error if those type constraints are not satisfied

So in our previous example, we can fix the trait using the @groovy.transform.SelfType annotation:

@SelfType(Device)
@CompileStatic
trait Communicating {
    void sendMessage(Device to, String message) {
        SecurityService.check(this)
        CommunicationService.sendMessage(id, to.id, message)
    }
}

Now if you try to implement this trait on a class that is not a device, a compile-time error will occur:

class MyDevice implements Communicating {} // forgot to extend Device

The error will be:

class 'MyDevice' implements trait 'Communicating' but does not extend self type class 'Device'

In conclusion, self types are a powerful way of declaring constraints on traits without having to declare the contract directly in the trait or having to use casts everywhere, maintaining separation of concerns as tight as it should be.

Limitations
Compatibility with AST transformations
Traits are not officially compatible with AST transformations. Some of them, like @CompileStatic will be applied on the trait itself (not on implementing classes), while others will apply on both the implementing class and the trait. There is absolutely no guarantee that an AST transformation will run on a trait as it does on a regular class, so use it at your own risk!
Prefix and postfix operations

Within traits, prefix and postfix operations are not allowed if they update a field of the trait:

trait Counting {
    int x
    void inc() {
        x++                             (1)
    }
    void dec() {
        --x                             (2)
    }
}
class Counter implements Counting {}
def c = new Counter()
c.inc()
1 x is defined within the trait, postfix increment is not allowed
2 x is defined within the trait, prefix decrement is not allowed

A workaround is to use the += operator instead.

1.5. Closures

This chapter covers Groovy Closures. A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope. In opposition to the formal definition of a closure, Closure in the Groovy language can also contain free variables which are defined outside of its surrounding scope. While breaking the formal concept of a closure, it offers a variety of advantages which are described in this chapter.

1.5.1. Syntax

Defining a closure

A closure definition follows this syntax:

{ [closureParameters -> ] statements }

Where [closureParameters->] is an optional comma-delimited list of parameters, and statements are 0 or more Groovy statements. The parameters look similar to a method parameter list, and these parameters may be typed or untyped.

When a parameter list is specified, the -> character is required and serves to separate the arguments from the closure body. The statements portion consists of 0, 1, or many Groovy statements.

Some examples of valid closure definitions:

{ item++ }                                          (1)

{ -> item++ }                                       (2)

{ println it }                                      (3)

{ it -> println it }                                (4)

{ name -> println name }                            (5)

{ String x, int y ->                                (6)
    println "hey ${x} the value is ${y}"
}

{ reader ->                                         (7)
    def line = reader.readLine()
    line.trim()
}
1 A closure referencing a variable named item
2 It is possible to explicitly separate closure parameters from code by adding an arrow (->)
3 A closure using an implicit parameter (it)
4 An alternative version where it is this time an explicit parameter
5 In that case it is often better to use an explicit name for the parameter
6 A closure accepting two typed parameters
7 A closure can contain multiple statements
Closures as an object

A closure is an instance of the groovy.lang.Closure class, making it assignable to a variable or a field as any other variable, despite being a block of code:

def listener = { e -> println "Clicked on $e.source" }      (1)
assert listener instanceof Closure
Closure callback = { println 'Done!' }                      (2)
Closure<Boolean> isTextFile = {
    File it -> it.name.endsWith('.txt')                     (3)
}
1 You can assign a closure to a variable, and it is an instance of groovy.lang.Closure
2 If not using def, you can assign a closure to a variable of type groovy.lang.Closure
3 Optionally, you can specify the return type of the closure by using the generic type of groovy.lang.Closure
Calling a closure

A closure, as an anonymous block of code, can be called like any other method. If you define a closure which takes no argument like this:

def code = { 123 }

Then the code inside the closure will only be executed when you call the closure, which can be done by using the variable as if it was a regular method:

assert code() == 123

Alternatively, you can be explicit and use the call method:

assert code.call() == 123

The principle is the same if the closure accepts arguments:

def isOdd = { int i-> i%2 == 1 }                            (1)
assert isOdd(3) == true                                     (2)
assert isOdd.call(2) == false                               (3)

def isEven = { it%2 == 0 }                                  (4)
assert isEven(3) == false                                   (5)
assert isEven.call(2) == true                               (6)
1 define a closure which accepts an int as a parameter
2 it can be called directly
3 or using the call method
4 same goes for a closure with an implicit argument (it)
5 which can be called directly using (arg)
6 or using call

Unlike a method, a closure always returns a value when called. The next section discusses how to declare closure arguments, when to use them and what is the implicit "it" parameter.

1.5.2. Parameters

Normal parameters

Parameters of closures follow the same principle as parameters of regular methods:

  • an optional type

  • a name

  • an optional default value

Parameters are separated with commas:

def closureWithOneArg = { str -> str.toUpperCase() }
assert closureWithOneArg('groovy') == 'GROOVY'

def closureWithOneArgAndExplicitType = { String str -> str.toUpperCase() }
assert closureWithOneArgAndExplicitType('groovy') == 'GROOVY'

def closureWithTwoArgs = { a,b -> a+b }
assert closureWithTwoArgs(1,2) == 3

def closureWithTwoArgsAndExplicitTypes = { int a, int b -> a+b }
assert closureWithTwoArgsAndExplicitTypes(1,2) == 3

def closureWithTwoArgsAndOptionalTypes = { a, int b -> a+b }
assert closureWithTwoArgsAndOptionalTypes(1,2) == 3

def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
assert closureWithTwoArgAndDefaultValue(1) == 3
Implicit parameter

When a closure does not explicitly define a parameter list (using ->), a closure always defines an implicit parameter, named it. This means that this code:

def greeting = { "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'

is stricly equivalent to this one:

def greeting = { it -> "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'

If you want to declare a closure which accepts no argument and must be restricted to calls without arguments, then you must declare it with an explicit empty argument list:

def magicNumber = { -> 42 }

// this call will fail because the closure doesn't accept any argument
magicNumber(11)
Varargs

It is possible for a closure to declare variable arguments like any other method. Vargs methods are methods that can accept a variable number of arguments if the last parameter is of variable length (or an array) like in the next examples:

def concat1 = { String... args -> args.join('') }           (1)
assert concat1('abc','def') == 'abcdef'                     (2)
def concat2 = { String[] args -> args.join('') }            (3)
assert concat2('abc', 'def') == 'abcdef'

def multiConcat = { int n, String... args ->                (4)
    args.join('')*n
}
assert multiConcat(2, 'abc','def') == 'abcdefabcdef'
1 A closure accepting a variable number of strings as first parameter
2 It may be called using any number of arguments without having to explicitly wrap them into an array
3 The same behavior is directly available if the args parameter is declared as an array
4 As long as the last parameter is an array of an explicit vargs type

1.5.3. Delegation strategy

Groovy closures vs lambda expressions

Groovy defines closures as instances of the Closure class. It makes it very different from lambda expressions in Java 8. Delegation is a key concept in Groovy closures which has no equivalent in lambdas. The ability to change the delegate or change the delegation strategy of closures make it possible to design beautiful domain specific languages (DSLs) in Groovy.

Owner, delegate and this

To understand the concept of delegate, we must first explain the meaning of this inside a closure. A closure actually defines 3 distinct things:

  • this corresponds to the enclosing class where the closure is defined

  • owner corresponds to the enclosing object where the closure is defined, which may be either a class or a closure

  • delegate corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined

The meaning of this

In a closure, calling getThisObject will return the enclosing class where the closure is defined. It is equivalent to using an explicit this:

class Enclosing {
    void run() {
        def whatIsThisObject = { getThisObject() }          (1)
        assert whatIsThisObject() == this                   (2)
        def whatIsThis = { this }                           (3)
        assert whatIsThis() == this                         (4)
    }
}
class EnclosedInInnerClass {
    class Inner {
        Closure cl = { this }                               (5)
    }
    void run() {
        def inner = new Inner()
        assert inner.cl() == inner                          (6)
    }
}
class NestedClosures {
    void run() {
        def nestedClosures = {
            def cl = { this }                               (7)
            cl()
        }
        assert nestedClosures() == this                     (8)
    }
}
1 a closure is defined inside the Enclosing class, and returns getThisObject
2 calling the closure will return the instance of Enclosing where the the closure is defined
3 in general, you will just want to use the shortcut this notation
4 and it returns exactly the same object
5 if the closure is defined in a inner class
6 this in the closure will return the inner class, not the top-level one
7 in case of nested closures, like here cl being defined inside the scope of nestedClosures
8 then this corresponds to the closest outer class, not the enclosing closure!

It is of course possible to call methods from the enclosing class this way:

class Person {
    String name
    int age
    String toString() { "$name is $age years old" }

    String dump() {
        def cl = {
            String msg = this.toString()               (1)
            println msg
            msg
        }
        cl()
    }
}
def p = new Person(name:'Janice', age:74)
assert p.dump() == 'Janice is 74 years old'
1 the closure calls toString on this, which will actually call the toString method on the enclosing object, that is to say the Person instance
Owner of a closure

The owner of a closure is very similar to the definition of this in a closure with a subtle difference: it will return the direct enclosing object, be it a closure or a class:

class Enclosing {
    void run() {
        def whatIsOwnerMethod = { getOwner() }               (1)
        assert whatIsOwnerMethod() == this                   (2)
        def whatIsOwner = { owner }                          (3)
        assert whatIsOwner() == this                         (4)
    }
}
class EnclosedInInnerClass {
    class Inner {
        Closure cl = { owner }                               (5)
    }
    void run() {
        def inner = new Inner()
        assert inner.cl() == inner                           (6)
    }
}
class NestedClosures {
    void run() {
        def nestedClosures = {
            def cl = { owner }                               (7)
            cl()
        }
        assert nestedClosures() == nestedClosures            (8)
    }
}
1 a closure is defined inside the Enclosing class, and returns getOwner
2 calling the closure will return the instance of Enclosing where the the closure is defined
3 in general, you will just want to use the shortcut owner notation
4 and it returns exactly the same object
5 if the closure is defined in a inner class
6 owner in the closure will return the inner class, not the top-level one
7 but in case of nested closures, like here cl being defined inside the scope of nestedClosures
8 then owner corresponds to the enclosing closure, hence a different object from this!
Delegate of a closure

The delegate of a closure can be accessed by using the delegate property or calling the getDelegate method. It is a powerful concept for building domain specific languages in Groovy. While closure-this and closure-owner refer to the lexical scope of a closure, the delegate is a user defined object that a closure will use. By default, the delegate is set to owner:

class Enclosing {
    void run() {
        def cl = { getDelegate() }                          (1)
        def cl2 = { delegate }                              (2)
        assert cl() == cl2()                                (3)
        assert cl() == this                                 (4)
        def enclosed = {
            { -> delegate }.call()                          (5)
        }
        assert enclosed() == enclosed                       (6)
    }
}
1 you can get the delegate of a closure calling the getDelegate method
2 or using the delegate property
3 both return the same object
4 which is the enclosing class or closure
5 in particular in case of nested closures
6 delegate will correspond to the owner

The delegate of a closure can be changed to any object. Let’s illustrate this by creating two classes which are not subclasses of each other but both define a property called name:

class Person {
    String name
}
class Thing {
    String name
}

def p = new Person(name: 'Norman')
def t = new Thing(name: 'Teapot')

Then let’s define a closure which fetches the name property on the delegate:

def upperCasedName = { delegate.name.toUpperCase() }

Then by changing the delegate of the closure, you can see that the target object will change:

upperCasedName.delegate = p
assert upperCasedName() == 'NORMAN'
upperCasedName.delegate = t
assert upperCasedName() == 'TEAPOT'

At this point, the behavior is not different from having a `variable defined in the lexical scope of the closure:

def target = p
def upperCasedNameUsingVar = { target.name.toUpperCase() }
assert upperCasedNameUsingVar() == 'NORMAN'

However there is are major differences:

  • in the last example, target is a local variable referenced from within the closure

  • the delegate can be used transparently, that is to say without prefixing method calls with delegate. as explained in the next paragraph.

Delegation strategy

Whenever, in a closure, a property is accessed without explicitly setting a receiver object, then a delegation strategy is involved:

class Person {
    String name
}
def p = new Person(name:'Igor')
def cl = { name.toUpperCase() }                 (1)
cl.delegate = p                                 (2)
assert cl() == 'IGOR'                           (3)
1 name is not referencing a variable in the lexical scope of the closure
2 we can change the delegate of the closure to be an instance of Person
3 and the method call will succeed

The reason this code works is that the name property will be resolved transparently on the delegate object! This is a very powerful way to resolve properties or method calls inside closures. There’s no need to set an explicit delegate. receiver: the call will be made because the default delegation strategy of the closure makes it so. A closure actually defines multiple resolution strategies that you can choose:

  • Closure.OWNER_FIRST is the default strategy. If a property/method exists on the owner, then it will be called on the owner. If not, then the delegate is used.

  • Closure.DELEGATE_FIRST reverses the logic: the delegate is used first, then the owner

  • Closure.OWNER_ONLY will only resolve the property/method lookup on the owner: the delegate will be ignored.

  • Closure.DELEGATE_ONLY will only resolve the property/method lookup on the delegate: the owner will be ignored.

  • Closure.TO_SELF can be used by developers who need advanced meta-programming techniques and wish to implement a custom resolution strategy: the resolution will not be made on the owner or the delegate but only on the closure class itself. It makes only sense to use this if you implement your own subclass of Closure.

Let’s illustrate the default "owner first" strategy with this code:

class Person {
    String name
    def pretty = { "My name is $name" }             (1)
    String toString() {
        pretty()
    }
}
class Thing {
    String name                                     (2)
}

def p = new Person(name: 'Sarah')
def t = new Thing(name: 'Teapot')

assert p.toString() == 'My name is Sarah'           (3)
p.pretty.delegate = t                               (4)
assert p.toString() == 'My name is Sarah'           (5)
1 for the illustration, we define a closure member which references "name"
2 both the Person and the Thing class define a name property
3 Using the default strategy, the name property is resolved on the owner first
4 so if we change the delegate to t which is an instance of Thing
5 there is no change in the result: name is first resolved on the owner of the closure

However, it is possible to change the resolution strategy of the closure:

p.pretty.resolveStrategy = Closure.DELEGATE_FIRST
assert p.toString() == 'My name is Teapot'

By changing the resolveStrategy, we are modifying the way Groovy will resolve the "implicit this" references: in this case, name will first be looked in the delegate, then if not found, on the owner. Since name is defined in the delegate, an instance of Thing, then this value is used.

The difference between "delegate first" and "delegate only" or "owner first" and "owner only" can be illustrated if one of the delegate (resp. owner) does not have such a method or property:

class Person {
    String name
    int age
    def fetchAge = { age }
}
class Thing {
    String name
}

def p = new Person(name:'Jessica', age:42)
def t = new Thing(name:'Printer')
def cl = p.fetchAge
cl.delegate = p
assert cl() == 42
cl.delegate = t
assert cl() == 42
cl.resolveStrategy = Closure.DELEGATE_ONLY
cl.delegate = p
assert cl() == 42
cl.delegate = t
try {
cl()
    assert false
} catch (MissingPropertyException ex) {
    // "age" is not defined on the delegate
}

In this example, we define two classes which both have a name property but only the Person class declares an age. The Person class also declares a closure which references age. We can change the default resolution strategy from "owner first" to "delegate only". Since the owner of the closure is the Person class, then we can check that if the delegate is an instance of Person, calling the closure is successful, but if we call it with a delegate being an instance of Thing, it fails with a groovy.lang.MissingPropertyException. Despite the closure being defined inside the Person class, the owner is not used.

A comprehensive explanation about how to use this feature to develop DSLs can be found in a dedicated section of the manual.

1.5.4. Closures in GStrings

Take the following code:

def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'

The code behaves as you would expect, but what happens if you add:

x = 2
assert gs == 'x = 2'

You will see that the assert fails! There are two reasons for this:

  • a GString only evaluates lazily the toString representation of values

  • the syntax ${x} in a GString does not represent a closure but an expression to $x, evaluated when the GString is created.

In our example, the GString is created with an expression referencing x. When the GString is created, the value of x is 1, so the GString is created with a value of 1. When the assert is triggered, the GString is evaluated and 1 is converted to a String using toString. When we change x to 2, we did change the value of x, but it is a different object, and the GString still references the old one.

A GString will only change its toString representation if the values it references are mutating. If the references change, nothing will happen.

If you need a real closure in a GString and for example enforce lazy evaluation of variables, you need to use the alternate syntax ${→ x} like in the fixed example:

def x = 1
def gs = "x = ${-> x}"
assert gs == 'x = 1'

x = 2
assert gs == 'x = 2'

And let’s illustrate how it differs from mutation with this code:

class Person {
    String name
    String toString() { name }          (1)
}
def sam = new Person(name:'Sam')        (2)
def lucy = new Person(name:'Lucy')      (3)
def p = sam                             (4)
def gs = "Name: ${p}"                   (5)
assert gs == 'Name: Sam'                (6)
p = lucy                                (7)
assert gs == 'Name: Sam'                (8)
sam.name = 'Lucy'                       (9)
assert gs == 'Name: Lucy'               (10)
1 the Person class has a toString method returning the name property
2 we create a first Person named Sam
3 we create another Person named Lucy
4 the p variable is set to Sam
5 and a closure is created, referencing the value of p, that is to say Sam
6 so when we evaluate the string, it returns Sam
7 if we change p to Lucy
8 the string still evaluates to Sam because it was the value of p when the GString was created
9 so if we mutate Sam to change his name to Lucy
10 this time the GString is correctly mutated

So if you don’t want to rely on mutating objects or wrapping objects, you must use closures in GString by explicitly declaring an empty argument list:

class Person {
    String name
    String toString() { name }
}
def sam = new Person(name:'Sam')
def lucy = new Person(name:'Lucy')
def p = sam
// Create a GString with lazy evaluation of "p"
def gs = "Name: ${-> p}"
assert gs == 'Name: Sam'
p = lucy
assert gs == 'Name: Lucy'

1.5.5. Closure coercion

Closures can be converted into interfaces or single-abstract method types. Please refer to this section of the manual for a complete description.

1.5.6. Functional programming

Closures, like lambda expressions in Java 8 are at the core of the functional programming paradigm in Groovy. Some functional programming operations on functions are available directly on the Closure class, like illustrated in this section.

Currying

In Groovy, currying refers to the concept of partial application. It does not correspond to the real concept of currying in functional programming because of the different scoping rules that Groovy applies on closures. Currying in Groovy will let you set the value of one parameter of a closure, and it will return a new closure accepting one less argument.

Left currying

Left currying is the fact of setting the left-most parameter of a closure, like in this example:

def nCopies = { int n, String str -> str*n }    (1)
def twice = nCopies.curry(2)                    (2)
assert twice('bla') == 'blabla'                 (3)
assert twice('bla') == nCopies(2, 'bla')        (4)
1 the nCopies closure defines two parameters
2 curry will set the first parameter to 2, creating a new closure (function) which accepts a single String
3 so the new function call be called with only a String
4 and it is equivalent to calling nCopies with two parameters
Right currying

Similarily to left currying, it is possible to set the right-most parameter of a closure:

def nCopies = { int n, String str -> str*n }    (1)
def blah = nCopies.rcurry('bla')                (2)
assert blah(2) == 'blabla'                      (3)
assert blah(2) == nCopies(2, 'bla')             (4)
1 the nCopies closure defines two parameters
2 rcurry will set the last parameter to bla, creating a new closure (function) which accepts a single int
3 so the new function call be called with only an int
4 and it is equivalent to calling nCopies with two parameters
Index based currying

In case a closure accepts more than 2 parameters, it is possible to set an arbitrary parameter using ncurry:

def volume = { double l, double w, double h -> l*w*h }      (1)
def fixedWidthVolume = volume.ncurry(1, 2d)                 (2)
assert volume(3d, 2d, 4d) == fixedWidthVolume(3d, 4d)       (3)
def fixedWidthAndHeight = volume.ncurry(1, 2d, 4d)          (4)
assert volume(3d, 2d, 4d) == fixedWidthAndHeight(3d)        (5)
1 the volume function defines 3 parameters
2 ncurry will set the second parameter (index = 1) to 2d, creating a new volume function which accepts length and height
3 that function is equivalent to calling volume omitting the width
4 it is also possible to set multiple parameters, starting from the specified index
5 the resulting function accepts as many parameters as the initial one minus the number of parameters set by ncurry
Memoization

Memoization allows the result of the call of a closure to be cached. It is interesting if the computation done by a function (closure) is slow, but you know that this function is going to be called often with the same arguments. A typical example is the Fibonacci suite. A naive implementation may look like this:

def fib
fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }
assert fib(15) == 610 // slow!

It is a naive implementation because 'fib' is often called recursively with the same arguments, leading to an exponential algorithm:

  • computing fib(15) requires the result of fib(14) and fib(13)

  • computing fib(14) requires the result of fib(13) and fib(12)

Since calls are recursive, you can already see that we will compute the same values again and again, although they could be cached. This naive implementation can be "fixed" by caching the result of calls using memoize:

fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }.memoize()
assert fib(25) == 75025 // fast!
The cache works using the actual values of the arguments. This means that you should be very careful if you use memoization with something else than primitive or boxed primitive types.

The behavior of the cache can be tweaked using alternate methods:

  • memoizeAtMost will generate a new closure which caches at most n values

  • memoizeAtLeast will generate a new closure which caches at least n values

  • memoizeBetween will generate a new closure which caches at least n values and at most n values

The cache used in all memoize variants is a LRU cache.

Composition

Closure composition corresponds to the concept of function composition, that is to say creating a new function by composing two or more functions (chaining calls), as illustrated in this example:

def plus2  = { it + 2 }
def times3 = { it * 3 }

def times3plus2 = plus2 << times3
assert times3plus2(3) == 11
assert times3plus2(4) == plus2(times3(4))

def plus2times3 = times3 << plus2
assert plus2times3(3) == 15
assert plus2times3(5) == times3(plus2(5))

// reverse composition
assert times3plus2(3) == (times3 >> plus2)(3)
Trampoline

Recursive algorithms are often restricted by a physical limit: the maximum stack height. For example, if you call a method that recursively calls itself too deep, you will eventually receive a StackOverflowException.

An approach that helps in those situations is by using Closure and its trampoline capability.

Closures are wrapped in a TrampolineClosure. Upon calling, a trampolined Closure will call the original Closure waiting for its result. If the outcome of the call is another instance of a TrampolineClosure, created perhaps as a result to a call to the trampoline() method, the Closure will again be invoked. This repetitive invocation of returned trampolined Closures instances will continue until a value other than a trampolined Closure is returned. That value will become the final result of the trampoline. That way, calls are made serially, rather than filling the stack.

Here’s an example of the use of trampoline() to implement the factorial function:

def factorial
factorial = { int n, def accu = 1G ->
    if (n < 2) return accu
    factorial.trampoline(n - 1, n * accu)
}
factorial = factorial.trampoline()

assert factorial(1)    == 1
assert factorial(3)    == 1 * 2 * 3
assert factorial(1000) // == 402387260.. plus another 2560 digits
Method pointers

It is often practical to be able to use a regular method as a closure. For example, you might want to use the currying abilities of a closure, but those are not available to normal methods. In Groovy, you can obtain a closure from any method with the method pointer operator.

1.6. Semantics

This chapter covers the semantics of the Groovy programming language.

1.6.1. Statements

Variable definition

Variables can be defined using either their type (like String) or by using the keyword def:

String x
def o

def is a replacement for a type name. In variable definitions it is used to indicate that you don’t care about the type. In variable definitions it is mandatory to either provide a type name explicitly or to use "def" in replacement. This is needed to make variable definitions detectable for the Groovy parser.

You can think of def as an alias of Object and you will understand it in an instant.

Variable definition types can be refined by using generics, like in List<String> names. To learn more about the generics support, please read the generics section.
Variable assignment

You can assign values to variables for later use. Try the following:

x = 1
println x

x = new java.util.Date()
println x

x = -3.1499392
println x

x = false
println x

x = "Hi"
println x
Multiple assignment

Groovy supports multiple assignment, i.e. where multiple variables can be assigned at once, e.g.:

def (a, b, c) = [10, 20, 'foo']
assert a == 10 && b == 20 && c == 'foo'

You can provide types as part of the declaration if you wish:

def (int i, String j) = [10, 'foo']
assert i == 10 && j == 'foo'

As well as used when declaring variables it also applies to existing variables:

def nums = [1, 3, 5]
def a, b, c
(a, b, c) = nums
assert a == 1 && b == 3 && c == 5

The syntax works for arrays as well as lists, as well as methods that return either of these:

def (_, month, year) = "18th June 2009".split()
assert "In $month of $year" == 'In June of 2009'
Overflow and Underflow

If the left hand side has too many variables, excess ones are filled with null’s:

def (a, b, c) = [1, 2]
assert a == 1 && b == 2 && c == null

If the right hand side has too many variables, the extra ones are ignored:

def (a, b) = [1, 2, 3]
assert a == 1 && b == 2
Object destructuring with multiple assignment

In the section describing the various Groovy operators, the case of the subscript operator has been covered, explaining how you can override the getAt()/putAt() method.

With this technique, we can combine multiple assignments and the subscript operator methods to implement object destructuring.

Consider the following immutable Coordinates class, containing a pair of longitude and latitude doubles, and notice our implementation of the getAt() method:

@Immutable
class Coordinates {
    double latitude
    double longitude

    double getAt(int idx) {
        if (idx == 0) latitude
        else if (idx == 1) longitude
        else throw new Exception("Wrong coordinate index, use 0 or 1")
    }
}

Now let’s instantiate this class and destructure its longitude and latitude:

def coordinates = new Coordinates(latitude: 43.23, longitude: 3.67) (1)

def (la, lo) = coordinates                                          (2)

assert la == 43.23                                                  (3)
assert lo == 3.67
1 we create an instance of the Coordinates class
2 then, we use a multiple assignment to get the individual longitude and latitude values
3 and we can finally assert their values.
Control structures
Conditional structures
if / else

Groovy supports the usual if - else syntax from Java

def x = false
def y = false

if ( !x ) {
    x = true
}

assert x == true

if ( x ) {
    x = false
} else {
    y = true
}

assert x == y

Groovy also supports the normal Java "nested" if then else if syntax:

if ( ... ) {
    ...
} else if (...) {
    ...
} else {
    ...
}
switch / case

The switch statement in Groovy is backwards compatible with Java code; so you can fall through cases sharing the same code for multiple matches.

One difference though is that the Groovy switch statement can handle any kind of switch value and different kinds of matching can be performed.

def x = 1.23
def result = ""

switch ( x ) {
    case "foo":
        result = "found foo"
        // lets fall through

    case "bar":
        result += "bar"

    case [4, 5, 6, 'inList']:
        result = "list"
        break

    case 12..30:
        result = "range"
        break

    case Integer:
        result = "integer"
        break

    case Number:
        result = "number"
        break

    case ~/fo*/: // toString() representation of x matches the pattern?
        result = "foo regex"
        break

    case { it < 0 }: // or { x < 0 }
        result = "negative"
        break

    default:
        result = "default"
}

assert result == "number"

Switch supports the following kinds of comparisons:

  • Class case values match if the switch value is an instance of the class

  • Regular expression case values match if the toString() representation of the switch value matches the regex

  • Collection case values match if the switch value is contained in the collection. This also includes ranges (since they are Lists)

  • Closure case values match if the calling the closure returns a result which is true according to the Groovy truth

  • If none of the above are used then the case value matches if the case value equals the switch value

default must go at the end of the switch/case. While in Java the default can be placed anywhere in the switch/case, the default in Groovy is used more as an else than assigning a default case.
when using a closure case value, the default it parameter is actually the switch value (in our example, variable x)
Looping structures
Classic for loop

Groovy supports the standard Java / C for loop:

String message = ''
for (int i = 0; i < 5; i++) {
    message += 'Hi '
}
assert message == 'Hi Hi Hi Hi Hi '
for in loop

The for loop in Groovy is much simpler and works with any kind of array, collection, Map, etc.

// iterate over a range
def x = 0
for ( i in 0..9 ) {
    x += i
}
assert x == 45

// iterate over a list
x = 0
for ( i in [0, 1, 2, 3, 4] ) {
    x += i
}
assert x == 10

// iterate over an array
def array = (0..4).toArray()
x = 0
for ( i in array ) {
    x += i
}
assert x == 10

// iterate over a map
def map = ['abc':1, 'def':2, 'xyz':3]
x = 0
for ( e in map ) {
    x += e.value
}
assert x == 6

// iterate over values in a map
x = 0
for ( v in map.values() ) {
    x += v
}
assert x == 6

// iterate over the characters in a string
def text = "abc"
def list = []
for (c in text) {
    list.add(c)
}
assert list == ["a", "b", "c"]
Groovy also supports the Java colon variation with colons: for (char c : text) {}, where the type of the variable is mandatory.
while loop

Groovy supports the usual while {…​} loops like Java:

def x = 0
def y = 5

while ( y-- > 0 ) {
    x++
}

assert x == 5
Exception handling

Exception handling is the same as Java.

try / catch / finally

You can specify a complete try-catch-finally, a try-catch, or a try-finally set of blocks.

Braces are required around each block’s body.
try {
    'moo'.toLong()   // this will generate an exception
    assert false     // asserting that this point should never be reached
} catch ( e ) {
    assert e in NumberFormatException
}

We can put code within a 'finally' clause following a matching 'try' clause, so that regardless of whether the code in the 'try' clause throws an exception, the code in the finally clause will always execute:

def z
try {
    def i = 7, j = 0
    try {
        def k = i / j
        assert false        //never reached due to Exception in previous line
    } finally {
        z = 'reached here'  //always executed even if Exception thrown
    }
} catch ( e ) {
    assert e in ArithmeticException
    assert z == 'reached here'
}
Multi-catch

With the multi catch block (since Groovy 2.0), we’re able to define several exceptions to be catch and treated by the same catch block:

try {
    /* ... */
} catch ( IOException | NullPointerException e ) {
    /* one block to handle 2 exceptions */
}
Power assertion

Unlike Java with which Groovy shares the assert keyword, the latter in Groovy behaves very differently. First of all, an assertion in Groovy is always executed, independently of the -ea flag of the JVM. It makes this a first class choice for unit tests. The notion of "power asserts" is directly related to how the Groovy assert behaves.

A power assertion is decomposed into 3 parts:

assert [left expression] == [right expression] : (optional message)

The result of the assertion is very different from what you would get in Java. If the assertion is true, then nothing happens. If the assertion is false, then it provides a visual representation of the value of each sub-expressions of the expression being asserted. For example:

assert 1+1 == 3

Will yield:

Caught: Assertion failed:

assert 1+1 == 3
        |  |
        2  false

Power asserts become very interesting when the expressions are more complex, like in the next example:

def x = 2
def y = 7
def z = 5
def calc = { a,b -> a*b+1 }
assert calc(x,y) == [x,z].sum()

Which will print the value for each sub-expression:

assert calc(x,y) == [x,z].sum()
       |    | |  |   | |  |
       15   2 7  |   2 5  7
                 false

In case you don’t want a pretty printed error message like above, you can fallback to a custom error message by changing the optional message part of the assertion, like in this example:

def x = 2
def y = 7
def z = 5
def calc = { a,b -> a*b+1 }
assert calc(x,y) == z*z : 'Incorrect computation result'

Which will print the following error message:

Incorrect computation result. Expression: (calc.call(x, y) == (z * z)). Values: z = 5, z = 5
Labeled statements

Any statement can be associated with a label. Labels do not impact the semantics of the code and can be used to make the code easier to read like in the following example:

given:
    def x = 1
    def y = 2
when:
    def z = x+y
then:
    assert z == 3

Despite not changing the semantics of the the labelled statement, it is possible to use labels in the break instruction as a target for jump, as in the next example. However, even if this is allowed, this coding style is in general considered a bad practice:

for (int i=0;i<10;i++) {
    for (int j=0;j<i;j++) {
        println "j=$j"
        if (j == 5) {
            break exit
        }
    }
    exit: println "i=$i"
}

It is important to understand that by default labels have no impact on the semantics of the code, however they belong to the abstract syntax tree (AST) so it is possible for an AST transformation to use that information to perform transformations over the code, hence leading to different semantics. This is in particular what the Spock Framework does to make testing easier.

1.6.2. Expressions

(TBD)

GPath expressions

GPath is a path expression language integrated into Groovy which allows parts of nested structured data to be identified. In this sense, it has similar aims and scope as XPath does for XML. GPath is often used in the context of processing XML, but it really applies to any object graph. Where XPath uses a filesystem-like path notation, a tree hierarchy with parts separated by a slash /, GPath use a dot-object notation to perform object navigation.

As an example, you can specify a path to an object or element of interest:

  • a.b.c → for XML, yields all the c elements inside b inside a

  • a.b.c → for POJOs, yields the c properties for all the b properties of a (sort of like a.getB().getC() in JavaBeans)

In both cases, the GPath expression can be viewed as a query on an object graph. For POJOs, the object graph is most often built by the program being written through object instantiation and composition; for XML processing, the object graph is the result of parsing the XML text, most often with classes like XmlParser or XmlSlurper. See Processing XML for more in-depth details on consuming XML in Groovy.

When querying the object graph generated from XmlParser or XmlSlurper, a GPath expression can refer to attributes defined on elements with the @ notation:

  • a["@href"] → map-like notation : the href attribute of all the a elements

  • a.'@href' → property notation : an alternative way of expressing this

  • a.@href → direct notation : yet another alternative way of expressing this

Object navigation

Let’s see an example of a GPath expression on a simple object graph, the one obtained using java reflection. Suppose you are in a non-static method of a class having another method named aMethodFoo

void aMethodFoo() { println "This is aMethodFoo." } (0)

the following GPath expression will get the name of that method:

assert ['aMethodFoo'] == this.class.methods.name.grep(~/.*Foo/)

More precisely, the above GPath expression produces a list of String, each being the name of an existing method on this where that name ends with Foo.

Now, given the following methods also defined in that class:

void aMethodBar() { println "This is aMethodBar." } (1)
void anotherFooMethod() { println "This is anotherFooMethod." } (2)
void aSecondMethodBar() { println "This is aSecondMethodBar." } (3)

then the following GPath expression will get the names of (1) and (3), but not (2) or (0):

assert ['aMethodBar', 'aSecondMethodBar'] as Set == this.class.methods.name.grep(~/.*Bar/) as Set
Expression Deconstruction

We can decompose the expression this.class.methods.name.grep(~/.*Bar/) to get an idea of how a GPath is evaluated:

this.class

property accessor, equivalent to this.getClass() in Java, yields a Class object.

this.class.methods

property accessor, equivalent to this.getClass().getMethods(), yields an array of Method objects.

this.class.methods.name

apply a property accessor on each element of an array and produce a list of the results.

this.class.methods.name.grep(…​)

call method grep on each element of the list yielded by this.class.methods.name and produce a list of the results.

a sub-expression like this.class.methods yields an array because this is what calling this.getClass().getMethods() in Java would produce : GPath expressions have not invented a convention where a s means a list or anything like that.

One powerful feature of GPath expression is that property access on a collection is converted to a property access on each element of the collection with the results collected into a collection. Therefore, the expression this.class.methods.name could be expressed as follows in Java:

List<String> methodNames = new ArrayList<String>();
for (Method method : this.getClass().getMethods()) {
   methodNames.add(method.getName());
}
return methodNames;

Array access notation can also be used in a GPath expression where a collection is present :

assert 'aSecondMethodBar' == this.class.methods.name.grep(~/.*Bar/).sort()[1]
array access are zero-based in GPath expressions
GPath for XML navigation

Here is an example with a XML document and various form of GPath expressions:

def xmlText = """
              | <root>
              |   <level>
              |      <sublevel id='1'>
              |        <keyVal>
              |          <key>mykey</key>
              |          <value>value 123</value>
              |        </keyVal>
              |      </sublevel>
              |      <sublevel id='2'>
              |        <keyVal>
              |          <key>anotherKey</key>
              |          <value>42</value>
              |        </keyVal>
              |        <keyVal>
              |          <key>mykey</key>
              |          <value>fizzbuzz</value>
              |        </keyVal>
              |      </sublevel>
              |   </level>
              | </root>
              """
def root = new XmlSlurper().parseText(xmlText.stripMargin())
assert root.level.size() == 1 (1)
assert root.level.sublevel.size() == 2 (2)
assert root.level.sublevel.findAll { it.@id == 1 }.size() == 1 (3)
assert root.level.sublevel[1].keyVal[0].key.text() == 'anotherKey' (4)
1 There is one level node under root
2 There are two sublevel nodes under root/level
3 There is one element sublevel having an attribute id with value 1
4 Text value of key element of first keyVal element of second sublevel element under root/level is 'anotherKey'

1.6.3. Promotion and coercion

Number promotion

The rules of number promotion are specified in the section on math operations.

Closure to type coercion
Assigning a closure to a SAM type

A SAM type is a type which defines a single abstract method. This includes:

Functional interfaces
interface Predicate<T> {
    boolean accept(T obj)
}
Abstract classes with single abstract method
abstract class Greeter {
    abstract String getName()
    void greet() {
        println "Hello, $name"
    }
}

Any closure can be converted into a SAM type using the as operator:

Predicate filter = { it.contains 'G' } as Predicate
assert filter.accept('Groovy') == true

Greeter greeter = { 'Groovy' } as Greeter
greeter.greet()

However, the as Type expression is optional since Groovy 2.2.0. You can omit it and simply write:

Predicate filter = { it.contains 'G' }
assert filter.accept('Groovy') == true

Greeter greeter = { 'Groovy' }
greeter.greet()

which means you are also allowed to use method pointers, as shown in the following example:

boolean doFilter(String s) { s.contains('G') }

Predicate filter = this.&doFilter
assert filter.accept('Groovy') == true

Greeter greeter = GroovySystem.&getVersion
greeter.greet()
Calling a method accepting a SAM type with a closure

The second and probably more important use case for closure to SAM type coercion is calling a method which accepts a SAM type. Imagine the following method:

public <T> List<T> filter(List<T> source, Predicate<T> predicate) {
    source.findAll { predicate.accept(it) }
}

Then you can call it with a closure, without having to create an explicit implementation of the interface:

assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate) == ['Groovy']

But since Groovy 2.2.0, you are also able to omit the explicit coercion and call the method as if it used a closure:

assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']

As you can see, this has the advantage of letting you use the closure syntax for method calls, that is to say put the closure outside of the parenthesis, improving the readability of your code.

Closure to arbitrary type coercion

In addition to SAM types, a closure can be coerced to any type and in particular interfaces. Let’s define the following interface:

interface FooBar {
    int foo()
    void bar()
}

You can coerce a closure into the interface using the as keyword:

def impl = { println 'ok'; 123 } as FooBar

This produces a class for which all methods are implemented using the closure:

assert impl.foo() == 123
impl.bar()

But it is also possible to coerce a closure to any class. For example, we can replace the interface that we defined with class without changing the assertions:

class FooBar {
    int foo() { 1 }
    void bar() { println 'bar' }
}

def impl = { println 'ok'; 123 } as FooBar

assert impl.foo() == 123
impl.bar()
Map to type coercion

Usually using a single closure to implement an interface or a class with multiple methods is not the way to go. As an alternative, Groovy allows you to coerce a map into an interface or a class. In that case, keys of the map are interpreted as method names, while the values are the method implementation. The following example illustrates the coercion of a map into an Iterator:

def map
map = [
  i: 10,
  hasNext: { map.i > 0 },
  next: { map.i-- },
]
def iter = map as Iterator

Of course this is a rather contrived example, but illustrates the concept. You only need to implement those methods that are actually called, but if a method is called that doesn’t exist in the map a MissingMethodException or an UnsupportedOperationException is thrown, depending on the arguments passed to the call, as in the following example:

interface X {
    void f()
    void g(int n)
    void h(String s, int n)
}

x = [ f: {println "f called"} ] as X
x.f() // method exists
x.g() // MissingMethodException here
x.g(5) // UnsupportedOperationException here

The type of the exception depends on the call itself:

  • MissingMethodException if the arguments of the call do not match those from the interface/class

  • UnsupportedOperationException if the arguments of the call match one of the overloaded methods of the interface/class

String to enum coercion

Groovy allows transparent String (or GString) to enum values coercion. Imagine you define the following enum:

enum State {
    up,
    down
}

then you can assign a string to the enum without having to use an explicit as coercion:

State st = 'up'
assert st == State.up

It is also possible to use a GString as the value:

def val = "up"
State st = "${val}"
assert st == State.up

However, this would throw a runtime error (IllegalArgumentException):

State st = 'not an enum value'

Note that it is also possible to use implicit coercion in switch statements:

State switchState(State st) {
    switch (st) {
        case 'up':
            return State.down // explicit constant
        case 'down':
            return 'up' // implicit coercion for return types
    }
}

in particular, see how the case use string constants. But if you call a method that uses an enum with a String argument, you still have to use an explicit as coercion:

assert switchState('up' as State) == State.down
assert switchState(State.down) == State.up
Custom type coercion

It is possible for a class to define custom coercion strategies by implementing the asType method. Custom coercion is invoked using the as operator and is never implicit. As an example, imagine you defined two classes, Polar and Cartesian, like in the following example:

class Polar {
    double r
    double phi
}
class Cartesian {
   double x
   double y
}

And that you want to convert from polar coordinates to cartesian coordinates. One way of doing this is to define the asType method in the Polar class:

def asType(Class target) {
    if (Cartesian==target) {
        return new Cartesian(x: r*cos(phi), y: r*sin(phi))
    }
}

which allows you to use the as coercion operator:

def sigma = 1E-16
def polar = new Polar(r:1.0,phi:PI/2)
def cartesian = polar as Cartesian
assert abs(cartesian.x-sigma) < sigma

Putting it all together, the Polar class looks like this:

class Polar {
    double r
    double phi
    def asType(Class target) {
        if (Cartesian==target) {
            return new Cartesian(x: r*cos(phi), y: r*sin(phi))
        }
    }
}

but it is also possible to define asType outside of the Polar class, which can be practical if you want to define custom coercion strategies for "closed" classes or classes for which you don’t own the source code, for example using a metaclass:

Polar.metaClass.asType = { Class target ->
    if (Cartesian==target) {
        return new Cartesian(x: r*cos(phi), y: r*sin(phi))
    }
}
Class literals vs variables and the as operator

Using the as keyword is only possible if you have a static reference to a class, like in the following code:

interface Greeter {
    void greet()
}
def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter is known statically
greeter.greet()

But what if you get the class by reflection, for example by calling Class.forName?

Class clazz = Class.forName('Greeter')

Trying to use the reference to the class with the as keyword would fail:

greeter = { println 'Hello, Groovy!' } as clazz
// throws:
// unable to resolve class clazz
// @ line 9, column 40.
//   greeter = { println 'Hello, Groovy!' } as clazz

It is failing because the as keyword only works with class literals. Instead, you need to call the asType method:

greeter = { println 'Hello, Groovy!' }.asType(clazz)
greeter.greet()

1.6.4. Optionality

Optional parentheses

Method calls can omit the parentheses if there is at least one parameter and there is no ambiguity:

println 'Hello World'
def maximum = Math.max 5, 10

Parentheses are required for method calls without parameters or ambiguous method calls:

println()
println(Math.max(5, 10))
Optional semicolons

In Groovy semicolons at the end of the line can be omitted, if the line contains only a single statement.

This means that:

assert true;

can be more idiomatically written as:

assert true

Multiple statements in a line require semicolons to separate them:

boolean a = true; assert a
Optional return keyword

In Groovy, the last expression evaluated in the body of a method or a closure is returned. This means that the return keyword is optional.

int add(int a, int b) {
    return a+b
}
assert add(1, 2) == 3

Can be shortened to:

int add(int a, int b) {
    a+b
}
assert add(1, 2) == 3
Optional public keyword

By default, Groovy classes and methods are public. Therefore this class:

public class Server {
    public String toString() { "a server" }
}

is identical to this class:

class Server {
    String toString() { "a server" }
}

1.6.5. The Groovy Truth

Groovy decides whether a expression is true or false by applying the rules given below.

Boolean expressions

True if the corresponding Boolean value is true.

assert true
assert !false
Collections

Non-empty Collections are true.

assert [1, 2, 3]
assert ![]
Matchers

True if the Matcher has at least one match.

assert ('a' =~ /a/)
assert !('a' =~ /b/)
Iterators and Enumerations

Iterators and Enumerations with further elements are coerced to true.

assert [0].iterator()
assert ![].iterator()
Vector v = [0] as Vector
Enumeration enumeration = v.elements()
assert enumeration
enumeration.nextElement()
assert !enumeration
Maps

Non-empty Maps are evaluated to true.

assert ['one' : 1]
assert ![:]
Strings

Non-empty Strings, GStrings and CharSequences are coerced to true.

assert 'a'
assert !''
def nonEmpty = 'a'
assert "$nonEmpty"
def empty = ''
assert !"$empty"
Numbers

Non-zero numbers are true.

assert 1
assert 3.5
assert !0
Object References

Non-null object references are coerced to true.

assert new Object()
assert !null
Customizing the truth with asBoolean() methods

In order to customize whether groovy evaluates your object to true or false implement the asBoolean() method:

class Color {
    String name

    boolean asBoolean(){
        name == 'green' ? true : false
    }
}

Groovy will call this method to coerce your object to a boolean value, e.g.:

assert new Color(name: 'green')
assert !new Color(name: 'red')

1.6.6. Typing

Optional typing

Optional typing is the idea that a program can work even if you don’t put an explicit type on a variable. Being a dynamic language, Groovy naturally implements that feature, for example when you declare a variable:

String aString = 'foo'                      (1)
assert aString.toUpperCase()                (2)
1 foo is declared using an explicit type, String
2 we can call the toUpperCase method on a String

Groovy will let you write this instead:

def aString = 'foo'                         (1)
assert aString.toUpperCase()                (2)
1 foo is declared using def
2 we can still call the toUpperCase method, because the type of aString is resolved at runtime

So it doesn’t matter that you use an explicit type here. It is in particular interesting when you combine this feature with static type checking, because the type checker performs type inference.

Likewise, Groovy doesn’t make it mandatory to declare the types of a parameter in a method:

String concat(String a, String b) {
    a+b
}
assert concat('foo','bar') == 'foobar'

can be rewritten using def as both return type and parameter types, in order to take advantage of duck typing, as illustrated in this example:

def concat(def a, def b) {                              (1)
    a+b
}
assert concat('foo','bar') == 'foobar'                  (2)
assert concat(1,2) == 3                                 (3)
1 both the return type and the parameter types use def
2 it makes it possible to use the method with String
3 but also with int since the plus method is defined
Using the def keyword here is recommended to describe the intent of a method which is supposed to work on any type, but technically, we could use Object instead and the result would be the same: def is, in Groovy, strictly equivalent to using Object.

Eventually, the type can be removed altogether from both the return type and the descriptor. But if you want to remove it from the return type, you then need to add an explicit modifier for the method, so that the compiler can make a difference between a method declaration and a method call, like illustrated in this example:

private concat(a,b) {                                   (1)
    a+b
}
assert concat('foo','bar') == 'foobar'                  (2)
assert concat(1,2) == 3                                 (3)
1 if we want to omit the return type, an explicit modifier has to be set.
2 it is still possible to use the method with String
3 and also with int
Omitting types is in general considered a bad practice in method parameters or method return types for public APIs. While using def in a local variable is not really a problem because the visibility of the variable is limited to the method itself, while set on a method parameter, def will be converted to Object in the method signature, making it difficult for users to know which is the expected type of the arguments. This means that you should limit this to cases where you are explicitly relying on duck typing.
Static type checking

By default, Groovy performs minimal type checking at compile time. Since it is primarily a dynamic language, most checks that a static compiler would normally do aren’t possible at compile time. A method added via runtime metaprogramming might alter a class or object’s runtime behavior. Let’s illustrate why in the following example:

class Person {                                                          (1)
    String firstName
    String lastName
}
def p = new Person(firstName: 'Raymond', lastName: 'Devos')             (2)
assert p.formattedName == 'Raymond Devos'                               (3)
1 the Person class only defines two properties, firstName and lastName
2 we can create an instance of Person
3 and call a method named formattedName

It is quite common in dynamic languages for code such as the above example not to throw any error. How can this be? In Java, this would typically fail at compile time. However, in Groovy, it will not fail at compile time, and if coded correctly, will also not fail at runtime. In fact, to make this work at runtime, one possibility is to rely on runtime metaprogramming. So just adding this line after the declaration of the Person class is enough:

Person.metaClass.getFormattedName = { "$delegate.firstName $delegate.lastName" }

This means that in general, in Groovy, you can’t make any assumption about the type of an object beyond its declaration type, and even if you know it, you can’t determine at compile time what method will be called, or which property will be retrieved. It has a lot of interest, going from writing DSLs to testing, which is discussed in other sections of this manual.

However, if your program doesn’t rely on dynamic features and that you come from the static world (in particular, from a Java mindset), not catching such "errors" at compile time can be surprising. As we have seen in the previous example, the compiler cannot be sure this is an error. To make it aware that it is, you have to explicitly instruct the compiler that you are switching to a type checked mode. This can be done by annotating a class or a method with @groovy.lang.TypeChecked.

When type checking is activated, the compiler performs much more work:

  • type inference is activated, meaning that even if you use def on a local variable for example, the type checker will be able to infer the type of the variable from the assignments

  • method calls are resolved at compile time, meaning that if a method is not declared on a class, the compiler will throw an error

  • in general, all the compile time errors that you are used to find in a static language will appear: method not found, property not found, incompatible types for method calls, number precision errors, …​

In this section, we will describe the behavior of the type checker in various situations and explain the limits of using @TypeChecked on your code.

The @TypeChecked annotation
Activating type checking at compile time

The groovy.lang.TypeChecked annotation enabled type checking. It can be placed on a class:

@groovy.transform.TypeChecked
class Calculator {
    int sum(int x, int y) { x+y }
}

Or on a method:

class Calculator {
    @groovy.transform.TypeChecked
    int sum(int x, int y) { x+y }
}

In the first case, all methods, properties, fields, inner classes, …​ of the annotated class will be type checked, whereas in the second case, only the method and potential closures or anonymous inner classes that it contains will be type checked.

Skipping sections

The scope of type checking can be restricted. For example, if a class is type checked, you can instruct the type checker to skip a method by annotating it with @TypeChecked(TypeCheckingMode.SKIP):

import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode

@TypeChecked                                        (1)
class GreetingService {
    String greeting() {                             (2)
        doGreet()
    }

    @TypeChecked(TypeCheckingMode.SKIP)             (3)
    private String doGreet() {
        def b = new SentenceBuilder()
        b.Hello.my.name.is.John                     (4)
        b
    }
}
def s = new GreetingService()
assert s.greeting() == 'Hello my name is John'
1 the GreetingService class is marked as type checked
2 so the greeting method is automatically type checked
3 but doGreet is marked with SKIP
4 the type checker doesn’t complain about missing properties here

In the previous example, SentenceBuilder relies on dynamic code. There’s no real Hello method or property, so the type checker would normally complain and compilation would fail. Since the method that uses the builder is marked with TypeCheckingMode.SKIP, type checking is skipped for this method, so the code will compile, even if the rest of the class is type checked.

The following sections describe the semantics of type checking in Groovy.

Type checking assignments

An object o of type A can be assigned to a variable of type T if and only if:

  • T equals A

    Date now = new Date()
  • or T is one of String, boolean, Boolean or Class

    String s = new Date() // implicit call to toString
    Boolean boxed = 'some string'       // Groovy truth
    boolean prim = 'some string'        // Groovy truth
    Class clazz = 'java.lang.String'    // class coercion
  • or o is null and T is not a primitive type

    String s = null         // passes
    int i = null            // fails
  • or T is an array and A is an array and the component type of A is assignable to the component type of T

    int[] i = new int[4]        // passes
    int[] i = new String[4]     // fails
  • or T is an array and A is a list and the component type of A is assignable to the component type of T

    int[] i = [1,2,3]               // passes
    int[] i = [1,2, new Date()]     // fails
  • or T is a superclass of A

    AbstractList list = new ArrayList()     // passes
    LinkedList list = new ArrayList()       // fails
  • or T is an interface implemented by A

    List list = new ArrayList()             // passes
    RandomAccess list = new LinkedList()    // fails
  • or T or A are a primitive type and their boxed types are assignable

    int i = 0
    Integer bi = 1
    int x = new Integer(123)
    double d = new Float(5f)
  • or T extends groovy.lang.Closure and A is a SAM-type (single abstract method type)

    Runnable r = { println 'Hello' }
    interface SAMType {
        int doSomething()
    }
    SAMType sam = { 123 }
    assert sam.doSomething() == 123
    abstract class AbstractSAM {
        int calc() { 2* value() }
        abstract int value()
    }
    AbstractSAM c = { 123 }
    assert c.calc() == 246
  • or T and A derive from java.lang.Number and conform to the following table

Table 2. Number types (java.lang.XXX)
T A Examples

Double

Any but BigDecimal or BigInteger

Double d1 = 4d
Double d2 = 4f
Double d3 = 4l
Double d4 = 4i
Double d5 = (short) 4
Double d6 = (byte) 4

Float

Any type but BigDecimal, BigInteger or Double

Float f1 = 4f
Float f2 = 4l
Float f3 = 4i
Float f4 = (short) 4
Float f5 = (byte) 4

Long

Any type but BigDecimal, BigInteger, Double or Float

Long l1 = 4l
Long l2 = 4i
Long l3 = (short) 4
Long l4 = (byte) 4

Integer

Any type but BigDecimal, BigInteger, Double, Float or Long

Integer i1 = 4i
Integer i2 = (short) 4
Integer i3 = (byte) 4

Short

Any type but BigDecimal, BigInteger, Double, Float, Long or Integer

Short s1 = (short) 4
Short s2 = (byte) 4

Byte

Byte

Byte b1 = (byte) 4
List and map constructors

In addition to the assignment rules above, if an assignment is deemed invalid, in type checked mode, a list literal or a map literal A can be assigned to a variable of type T if:

  • the assignment is a variable declaration and A is a list literal and T has a constructor whose parameters match the types of the elements in the list literal

  • the assignment is a variable declaration and A is a map literal and T has a no-arg constructor and a property for each of the map keys

For example, instead of writing:

@groovy.transform.TupleConstructor
class Person {
    String firstName
    String lastName
}
Person classic = new Person('Ada','Lovelace')

You can use a "list constructor":

Person list = ['Ada','Lovelace']

or a "map constructor":

Person map = [firstName:'Ada', lastName:'Lovelace']

If you use a map constructor, additional checks are done on the keys of the map to check if a property of the same name is defined. For example, the following will fail at compile time:

@groovy.transform.TupleConstructor
class Person {
    String firstName
    String lastName
}
Person map = [firstName:'Ada', lastName:'Lovelace', age: 24]     (1)
1 The type checker will throw an error No such property: age for class: Person at compile time
Method resolution

In type checked mode, methods are resolved at compile time. Resolution works by name and arguments. The return type is irrelevant to method selection. Types of arguments are matched against the types of the parameters following those rules:

An argument o of type A can be used for a parameter of type T if and only if:

  • T equals A

    int sum(int x, int y) {
        x+y
    }
    assert sum(3,4) == 7
  • or T is a String and A is a GString

    String format(String str) {
        "Result: $str"
    }
    assert format("${3+4}") == "Result: 7"
  • or o is null and T is not a primitive type

    String format(int value) {
        "Result: $value"
    }
    assert format(7) == "Result: 7"
    format(null)           // fails
  • or T is an array and A is an array and the component type of A is assignable to the component type of T

    String format(String[] values) {
        "Result: ${values.join(' ')}"
    }
    assert format(['a','b'] as String[]) == "Result: a b"
    format([1,2] as int[])              // fails
  • or T is a superclass of A

    String format(AbstractList list) {
        list.join(',')
    }
    format(new ArrayList())              // passes
    String format(LinkedList list) {
        list.join(',')
    }
    format(new ArrayList())              // fails
  • or T is an interface implemented by A

    String format(List list) {
        list.join(',')
    }
    format(new ArrayList())                  // passes
    String format(RandomAccess list) {
        'foo'
    }
    format(new LinkedList())                 // fails
  • or T or A are a primitive type and their boxed types are assignable

    int sum(int x, Integer y) {
        x+y
    }
    assert sum(3, new Integer(4)) == 7
    assert sum(new Integer(3), 4) == 7
    assert sum(new Integer(3), new Integer(4)) == 7
    assert sum(new Integer(3), 4) == 7
  • or T extends groovy.lang.Closure and A is a SAM-type (single abstract method type)

    interface SAMType {
        int doSomething()
    }
    int twice(SAMType sam) { 2*sam.doSomething() }
    assert twice { 123 } == 246
    abstract class AbstractSAM {
        int calc() { 2* value() }
        abstract int value()
    }
    int eightTimes(AbstractSAM sam) { 4*sam.calc() }
    assert eightTimes { 123 } == 984
  • or T and A derive from java.lang.Number and conform to the same rules as assignment of numbers

If a method with the appropriate name and arguments is not found at compile time, an error is thrown. The difference with "normal" Groovy is illustrated in the following example:

class MyService {
    void doSomething() {
        printLine 'Do something'            (1)
    }
}
1 printLine is an error, but since we’re in a dynamic mode, the error is not caught at compile time

The example above shows a class that Groovy will be able to compile. However, if you try to create an instance of MyService and call the doSomething method, then it will fail at runtime, because printLine doesn’t exist. Of course, we already showed how Groovy could make this a perfectly valid call, for example by catching MethodMissingException or implementing a custom meta-class, but if you know you’re not in such a case, @TypeChecked comes handy:

@groovy.transform.TypeChecked
class MyService {
    void doSomething() {
        printLine 'Do something'            (1)
    }
}
1 printLine is this time a compile-time error

Just adding @TypeChecked will trigger compile time method resolution. The type checker will try to find a method printLine accepting a String on the MyService class, but cannot find one. It will fail compilation with the following message:

Cannot find matching method MyService#printLine(java.lang.String)

It is important to understand the logic behind the type checker: it is a compile-time check, so by definition, the type checker is not aware of any kind of runtime metaprogramming that you do. This means that code which is perfectly valid without @TypeChecked will not compile anymore if you activate type checking. This is in particular true if you think of duck typing:
class Duck {
    void quack() {              (1)
        println 'Quack!'
    }
}
class QuackingBird {
    void quack() {              (2)
        println 'Quack!'
    }
}
@groovy.transform.TypeChecked
void accept(quacker) {
    quacker.quack()             (3)
}
accept(new Duck())              (4)
1 we define a Duck class which defines a quack method
2 we define another QuackingBird class which also defines a quack method
3 quacker is loosely typed, so since the method is @TypeChecked, we will obtain a compile-time error
4 even if in non type-checked Groovy, this would have passed

There are possible workarounds, like introducing an interface, but basically, by activating type checking, you gain type safety but you loose some features of the language. Hopefully, Groovy introduces some features like flow typing to reduce the gap between type-checked and non type-checked Groovy.

Type inference
Principles

When code is annotated with @TypeChecked, the compiler performs type inference. It doesn’t simply rely on static types, but also uses various techniques to infer the types of variables, return types, literals, …​ so that the code remains as clean as possible even if you activate the type checker.

The simplest example is inferring the type of a variable:

def message = 'Welcome to Groovy!'              (1)
println message.toUpperCase()                   (2)
println message.upper() // compile time error   (3)
1 a variable is declared using the def keyword
2 calling toUpperCase is allowed by the type checker
3 calling upper will fail at compile time

The reason the call to toUpperCase works is because the type of message was inferred as being a String.

Variables vs fields in type inference

It is worth noting that although the compiler performs type inference on local variables, it does not perform any kind of type inference on fields, always falling back to the declared type of a field. To illustrate this, let’s take a look at this example:

class SomeClass {
    def someUntypedField                                                                (1)
    String someTypedField                                                               (2)

    void someMethod() {
        someUntypedField = '123'                                                        (3)
        someUntypedField = someUntypedField.toUpperCase()  // compile-time error        (4)
    }

    void someSafeMethod() {
        someTypedField = '123'                                                          (5)
        someTypedField = someTypedField.toUpperCase()                                   (6)
    }

    void someMethodUsingLocalVariable() {
        def localVariable = '123'                                                       (7)
        someUntypedField = localVariable.toUpperCase()                                  (8)
    }
}
1 someUntypedField uses def as a declaration type
2 someTypedField uses String as a declaration type
3 we can assign anything to someUntypedField
4 yet calling toUpperCase fails at compile time because the field is not typed properly
5 we can assign a String to a field of type String
6 and this time toUpperCase is allowed
7 if we assign a String to a local variable
8 then calling toUpperCase is allowed on the local variable

Why such a difference? The reason is thread safety. At compile time, we can’t make any guarantee about the type of a field. Any thread can access any field at any time and between the moment a field is assigned a variable of some type in a method and the time is is used the line after, another thread may have changed the contents of the field. This is not the case for local variables: we know if they "escape" or not, so we can make sure that the type of a variable is constant (or not) over time. Note that even if a field is final, the JVM makes no guarantee about it, so the type checker doesn’t behave differently if a field is final or not.

This is one of the reasons why we recommend to use typed fields. While using def for local variables is perfectly fine thanks to type inference, this is not the case for fields, which also belong to the public API of a class, hence the type is important.
Collection literal type inference

Groovy provides a syntax for various type literals. There are three native collection literals in Groovy:

  • lists, using the [] literal

  • maps, using the [:] literal

  • ranges, using the (..,..) literal

The inferred type of a literal depends on the elements of the literal, as illustrated in the following table:

Literal Inferred type
def list = []

java.util.List

def list = ['foo','bar']

java.util.List<String>

def list = ["${foo}","${bar}"]

java.util.List<GString> be careful, a GString is not a String!

def map = [:]

java.util.LinkedHashMap

def map1 = [someKey: 'someValue']
def map2 = ['someKey': 'someValue']

java.util.LinkedHashMap<String,String>

def map = ["${someKey}": 'someValue']

java.util.LinkedHashMap<GString,String> be careful, the key is a GString!

def intRange = (0..10)

groovy.lang.IntRange

def charRange = ('a'..'z')

groovy.lang.Range<String> : uses the type of the bounds to infer the component type of the range

As you can see, with the noticeable exception of the IntRange, the inferred type makes use of generics types to describe the contents of a collection. In case the collection contains elements of different types, the type checker still performs type inference of the components, but uses the notion of least upper bound.

Least upper bound

In Groovy, the least upper bound of two types A and B is defined as a type which:

  • superclass corresponds to the common super class of A and B

  • interfaces correspond to the interfaces implemented by both A and B

  • if A or B is a primitive type and that A isn’t equal to B, the least upper bound of A and B is the least upper bound of their wrapper types

If A and B only have one (1) interface in common and that their common superclass is Object, then the LUB of both is the common interface.

The least upper bound represents the minimal type to which both A and B can be assigned. So for example, if A and B are both String, then the LUB (least upper bound) of both is also String.

class Top {}
class Bottom1 extends Top {}
class Bottom2 extends Top {}

assert leastUpperBound(String, String) == String                    (1)
assert leastUpperBound(ArrayList, LinkedList) == AbstractList       (2)
assert leastUpperBound(ArrayList, List) == List                     (3)
assert leastUpperBound(List, List) == List                          (4)
assert leastUpperBound(Bottom1, Bottom2) == Top                     (5)
assert leastUpperBound(List, Serializable) == Object                (6)
1 the LUB of String and String is String
2 the LUB of ArrayList and LinkedList is their common super type, AbstractList
3 the LUB of ArrayList and List is their only common interface, List
4 the LUB of two identical interfaces is the interface itself
5 the LUB of Bottom1 and Bottom2 is their superclass Top
6 the LUB of two types which have nothing in common is Object

In those examples, the LUB is always representable as a normal, JVM supported, type. But Groovy internally represents the LUB as a type which can be more complex, and that you wouldn’t be able to use to define a variable for example. To illustrate this, let’s continue with this example:

interface Foo {}
class Top {}
class Bottom extends Top implements Serializable, Foo {}
class SerializableFooImpl implements Serializable, Foo {}

What is the least upper bound of Bottom and SerializableFooImpl? They don’t have a common super class (apart from Object), but they do share 2 interfaces (Serializable and Foo), so their least upper bound is a type which represents the union of two interfaces (Serializable and Foo). This type cannot be defined in the source code, yet Groovy knows about it.

In the context of collection type inference (and generic type inference in general), this becomes handy, because the type of the components is inferred as the least upper bound. We can illustrate why this is important in the following example:

interface Greeter { void greet() }                  (1)
interface Salute { void salute() }                  (2)

class A implements Greeter, Salute {                (3)
    void greet() { println "Hello, I'm A!" }
    void salute() { println "Bye from A!" }
}
class B implements Greeter, Salute {                (4)
    void greet() { println "Hello, I'm B!" }
    void salute() { println "Bye from B!" }
    void exit() { println 'No way!' }               (5)
}
def list = [new A(), new B()]                       (6)
list.each {
    it.greet()                                      (7)
    it.salute()                                     (8)
    it.exit()                                       (9)
}
1 the Greeter interface defines a single method, greet
2 the Salute interface defines a single method, salute
3 class A implements both Greeter and Salute but there’s no explicit interface extending both
4 same for B
5 but B defines an additional exit method
6 the type of list is inferred as "list of the LUB of A and `B`"
7 so it is possible to call greet which is defined on both A and B through the Greeter interface
8 and it is possible to call salute which is defined on both A and B through the Salute interface
9 yet calling exit is a compile time error because it doesn’t belong to the LUB of A and B (only defined in B)

The error message will look like:

[Static type checking] - Cannot find matching method Greeter or Salute#exit()

which indicates that the exit method is neither defines on Greeter nor Salute, which are the two interfaces defined in the least upper bound of A and B.

instanceof inference

In normal, non type checked, Groovy, you can write things like:

class Greeter {
    String greeting() { 'Hello' }
}

void doSomething(def o) {
    if (o instanceof Greeter) {     (1)
        println o.greeting()        (2)
    }
}

doSomething(new Greeter())
1 guard the method call with an instanceof check
2 make the call

The method call works because of dynamic dispatch (the method is selected at runtime). The equivalent code in Java would require to cast o to a Greeter before calling the greeting method, because methods are selected at compile time:

if (o instanceof Greeter) {
    System.out.println(((Greeter)o).greeting());
}

However, in Groovy, even if you add @TypeChecked (and thus activate type checking) on the doSomething method, the cast is not necessary. The compiler embeds instanceof inference that makes the cast optional.

Flow typing

Flow typing is an important concept of Groovy in type checked mode and an extension of type inference. The idea is that the compiler is capable of inferring the type of variables in the flow of the code, not just at initialization:

@groovy.transform.TypeChecked
void flowTyping() {
    def o = 'foo'                       (1)
    o = o.toUpperCase()                 (2)
    o = 9d                              (3)
    o = Math.sqrt(o)                    (4)
}
1 first, o is declared using def and assigned a String
2 the compiler inferred that o is a String, so calling toUpperCase is allowed
3 o is reassigned with a double
4 calling Math.sqrt passes compilation because the compiler knows that at this point, o is a double

So the type checker is aware of the fact that the concrete type of a variable is different over time. In particular, if you replace the last assignment with:

o = 9d
o = o.toUpperCase()

The type checker will now fail at compile time, because it knows that o is a double when toUpperCase is called, so it’s a type error.

It is important to understand that it is not the fact of declaring a variable with def that triggers type inference. Flow typing works for any variable of any type. Declaring a variable with an explicit type only constraints what you can assign to a variable:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List list = ['a','b','c']           (1)
    list = list*.toUpperCase()          (2)
    list = 'foo'                        (3)
}
1 list is declared as an unchecked List and assigned a list literal of `String`s
2 this line passes compilation because of flow typing: the type checker knows that list is at this point a List<String>
3 but you can’t assign a String to a List so this is a type checking error

You can also note that even if the variable is declared without generics information, the type checker knows what is the component type. Therefore, such code would fail compilation:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List list = ['a','b','c']           (1)
    list.add(1)                         (2)
}
1 list is inferred as List<String>
2 so adding an int to a List<String> is a compile-time error

Fixing this requires adding an explicit generic type to the declaration:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List<? extends Serializable> list = []                      (1)
    list.addAll(['a','b','c'])                                  (2)
    list.add(1)                                                 (3)
}
1 list declared as List<? extends Serializable> and initialized with an empty list
2 elements added to the list conform to the declaration type of the list
3 so adding an int to a List<? extends Serializable> is allowed

Flow typing has been introduced to reduce the difference in semantics between classic and static Groovy. In particular, consider the behavior of this code in Java:

public Integer compute(String str) {
    return str.length();
}
public String compute(Object o) {
    return "Nope";
}
// ...
Object string = "Some string";          (1)
Object result = compute(string);        (2)
System.out.println(result);             (3)
1 o is declared as an Object and assigned a String
2 we call the compute method with o
3 and print the result

In Java, this code will output Nope, because method selection is done at compile time and based on the declared types. So even if o is a String at runtime, it is still the Object version which is called, because o has been declared as an Object. To be short, in Java, declared types are most important, be it variable types, parameter types or return types.

In Groovy, we could write:

int compute(String string) { string.length() }
String compute(Object o) { "Nope" }
Object o = 'string'
def result = compute(o)
println result

But this time, it will return 6, because the method which is chosen is chosen at runtime, based on the actual argument types. So at runtime, o is a String so the String variant is used. Note that this behavior has nothing to do with type checking, it’s the way Groovy works in general: dynamic dispatch.

In type checked Groovy, we want to make sure the type checker selects the same method at compile time, that the runtime would choose. It is not possible in general, due to the semantics of the language, but we can make things better with flow typing. With flow typing, o is inferred as a String when the compute method is called, so the version which takes a String and returns an int is chosen. This means that we can infer the return type of the method to be an int, and not a String. This is important for subsequent calls and type safety.

So in type checked Groovy, flow typing is a very important concept, which also implies that if @TypeChecked is applied, methods are selected based on the inferred types of the arguments, not on the declared types. This doesn’t ensure 100% type safety, because the type checker may select a wrong method, but it ensures the closest semantics to dynamic Groovy.

Advanced type inference

A combination of flow typing and least upper bound inference is used to perform advanced type inference and ensure type safety in multiple situations. In particular, program control structures are likely to alter the inferred type of a variable:

class Top {
   void methodFromTop() {}
}
class Bottom extends Top {
   void methodFromBottom() {}
}
def o
if (someCondition) {
    o = new Top()                               (1)
} else {
    o = new Bottom()                            (2)
}
o.methodFromTop()                               (3)
o.methodFromBottom()  // compilation error      (4)
1 if someCondition is true, o is assigned a Top
2 if someCondition is false, o is assigned a Bottom
3 calling methodFromTop is safe
4 but calling methodFromBottom is not, so it’s a compile time error

When the type checker visits an if/else control structure, it checks all variables which are assigned in if/else branches and computes the least upper bound of all assignments. This type is the type of the inferred variable after the if/else block, so in this example, o is assigned a Top in the if branch and a Bottom in the else branch. The LUB of those is a Top, so after the conditional branches, the compiler infers o as being a Top. Calling methodFromTop will therefore be allowed, but not methodFromBottom.

The same reasoning exists with closures and in particular closure shared variables. A closure shared variable is a variable which is defined outside of a closure, but used inside a closure, as in this example:

def text = 'Hello, world!'                          (1)
def closure = {
    println text                                    (2)
}
1 a variable named text is declared
2 text is used from inside a closure. It is a closure shared variable.

Groovy allows developers to use those variables without requiring them to be final. This means that a closure shared variable can be reassigned inside a closure:

String result
doSomething { String it ->
    result = "Result: $it"
}
result = result?.toUpperCase()

The problem is that a closure is an independent block of code that can be executed (or not) at any time. In particular, doSomething may be asynchronous, for example. This means that the body of a closure doesn’t belong to the main control flow. For that reason, the type checker also computes, for each closure shared variable, the LUB of all assignments of the variable, and will use that LUB as the inferred type outside of the scope of the closure, like in this example:

class Top {
   void methodFromTop() {}
}
class Bottom extends Top {
   void methodFromBottom() {}
}
def o = new Top()                               (1)
Thread.start {
    o = new Bottom()                            (2)
}
o.methodFromTop()                               (3)
o.methodFromBottom()  // compilation error      (4)
1 a closure-shared variable is first assigned a Top
2 inside the closure, it is assigned a Bottom
3 methodFromTop is allowed
4 methodFromBottom is a compilation error

Here, it is clear that when methodFromBottom is called, there’s no guarantee, at compile-time or runtime that the type of o will effectively be a Bottom. There are chances that it will be, but we can’t make sure, because it’s asynchronous. So the type checker will only allow calls on the least upper bound, which is here a Top.

Closures and type inference

The type checker performs special inference on closures, resulting on additional checks on one side and improved fluency on the other side.

Return type inference

The first thing that the type checker is capable of doing is inferring the return type of a closure. This is simply illustrated in the following example:

@groovy.transform.TypeChecked
int testClosureReturnTypeInference(String arg) {
    def cl = { "Arg: $arg" }                                (1)
    def val = cl()                                          (2)

    val.length()                                            (3)
}
1 a closure is defined, and it returns a string (more precisely a GString)
2 we call the closure and assign the result to a variable
3 the type checker inferred that the closure would return a string, so calling length() is allowed

As you can see, unlike a method which declares its return type explicitly, there’s no need to declare the return type of a closure: its type is inferred from the body of the closure.

Closures vs methods

It’s worth noting that return type inference is only applicable to closures. While the type checker could do the same on a method, it is in practice not desirable: in general, methods can be overriden and it is not statically possible to make sure that the method which is called is not an overriden version. So flow typing would actually think that a method returns something, while in reality, it could return something else, like illustrated in the following example:

@TypeChecked
class A {
    def compute() { 'some string' }             (1)
    def computeFully() {
        compute().toUpperCase()                 (2)
    }
}
@TypeChecked
class B extends A {
    def compute() { 123 }                       (3)
}
1 class A defines a method compute which effectively returns a String
2 this will fail compilation because the return type of compute is def(aka Object)
3 class B extends A and redefines compute, this type returning an int

As you can see, if the type checker relied on the inferred return type of a method, with flow typing, the type checker could determine that it is ok to call toUpperCase. It is in fact an error, because a subclass can override compute and return a different object. Here, B#compute returns an int, so someone calling computeFully on an instance of B would see a runtime error. The compiler prevents this from happening by using the declared return type of methods instead of the inferred return type.

For consistency, this behavior is the same for every method, even if they are static or final.

Parameter type inference

In addition to the return type, it is possible for a closure to infer its parameter types from the context. There are two ways for the compiler to infer the parameter types:

  • through implicit SAM type coercion

  • through API metadata

To illustrate this, lets start with an example that will fail compilation due to the inability for the type checker to infer the parameter types:

class Person {
    String name
    int age
}

void inviteIf(Person p, Closure<Boolean> predicate) {           (1)
    if (predicate.call(p)) {
        // send invite
        // ...
    }
}

@groovy.transform.TypeChecked
void failCompilation() {
    Person p = new Person(name: 'Gerard', age: 55)
    inviteIf(p) {                                               (2)
        it.age >= 18 // No such property: age                   (3)
    }
}
1 the inviteIf method accepts a Person and a Closure
2 we call it with a Person and a Closure
3 yet it is not statically known as being a Person and compilation fails

In this example, the closure body contains it.age. With dynamic, not type checked code, this would work, because the type of it would be a Person at runtime. Unfortunately, at compile-time, there’s no way to know what is the type of it, just by reading the signature of inviteIf.

Explicit closure parameters

To be short, the type checker doesn’t have enough contextual information on the inviteIf method to determine statically the type of it. This means that the method call needs to be rewritten like this:

inviteIf(p) { Person it ->                                  (1)
    it.age >= 18
}
1 the type of it needs to be declared explicitly

By explicitly declaring the type of the it variable, you can workaround the problem and make this code statically checked.

Parameters inferred from single-abstract method types

For an API or framework designer, there are two ways to make this more elegant for users, so that they don’t have to declare an explicit type for the closure parameters. The first one, and easiest, is to replace the closure with a SAM type:

interface Predicate<On> { boolean apply(On e) }                 (1)

void inviteIf(Person p, Predicate<Person> predicate) {          (2)
    if (predicate.apply(p)) {
        // send invite
        // ...
    }
}

@groovy.transform.TypeChecked
void passesCompilation() {
    Person p = new Person(name: 'Gerard', age: 55)

    inviteIf(p) {                                               (3)
        it.age >= 18                                            (4)
    }
}
1 declare a SAM interface with an apply method
2 inviteIf now uses a Predicate<Person> instead of a Closure<Boolean>
3 there’s no need to declare the type of the it variable anymore
4 it.age compiles properly, the type of it is inferred from the Predicate#apply method signature
By using this technique, we leverage the automatic coercion of closures to SAM types feature of Groovy. The question whether you should use a SAM type or a Closure really depends on what you need to do. In a lot of cases, using a SAM interface is enough, especially if you consider functional interfaces as they are found in Java 8. However, closures provide features that are not accessible to functional interfaces. In particular, closures can have a delegate, and owner and can be manipulated as objects (for example, cloned, serialized, curried, …​) before being called. They can also support multiple signatures (polymorphism). So if you need that kind of manipulation, it is preferable to switch to the most advanced type inference annotations which are described below.

The original issue that needs to be solved when it comes to closure parameter type inference, that is to say, statically determining the types of the arguments of a closure without having to have them explicitly declared, is that the Groovy type system inherits the Java type system, which is insufficient to describe the types of the arguments.

The @ClosureParams annotation

Groovy provides an annotation, @ClosureParams which is aimed at completing type information. This annotation is primarily aimed at framework and API developers who want to extend the capabilities of the type checker by providing type inference metadata. This is important if your library makes use of closures and that you want the maximum level of tooling support too.

Let’s illustrate this by fixing the original example, introducing the @ClosureParams annotation:

import groovy.transform.stc.ClosureParams
import groovy.transform.stc.FirstParam
void inviteIf(Person p, @ClosureParams(FirstParam) Closure<Boolean> predicate) {        (1)
    if (predicate.call(p)) {
        // send invite
        // ...
    }
}
inviteIf(p) {                                                                       (2)
    it.age >= 18
}
1 the closure parameter is annotated with @ClosureParams
2 it’s not necessary to use an explicit type for it, which is inferred

The @ClosureParams annotation minimally accepts one argument, which is named a type hint. A type hint is a class which is responsible for completing type information at compile time for the closure. In this example, the type hint being used is groovy.transform.stc.FirstParam which indicated to the type checker that the closure will accept one parameter whose type is the type of the first parameter of the method. In this case, the first parameter of the method is Person, so it indicates to the type checker that the first parameter of the closure is in fact a Person.

The second argument is optional and named options. It’s semantics depends on the type hint class. Groovy comes with various bundled type hints, illustrated in the table below:

Table 3. Predefined type hints
Type hint Polymorphic? Description and examples

FirstParam
SecondParam
ThirdParam

No

The first (resp. second, third) parameter type of the method

import groovy.transform.stc.FirstParam
void doSomething(String str, @ClosureParams(FirstParam) Closure c) {
    c(str)
}
doSomething('foo') { println it.toUpperCase() }
import groovy.transform.stc.SecondParam
void withHash(String str, int seed, @ClosureParams(SecondParam) Closure c) {
    c(31*str.hashCode()+seed)
}
withHash('foo', (int)System.currentTimeMillis()) {
    int mod = it%2
}
import groovy.transform.stc.ThirdParam
String format(String prefix, String postfix, String o, @ClosureParams(ThirdParam) Closure c) {
    "$prefix${c(o)}$postfix"
}
assert format('foo', 'bar', 'baz') {
    it.toUpperCase()
} == 'fooBAZbar'

FirstParam.FirstGenericType
SecondParam.FirstGenericType
ThirdParam.FirstGenericType

No

The first generic type of the first (resp. second, third) parameter of the method

import groovy.transform.stc.FirstParam
public <T> void doSomething(List<T> strings, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
    strings.each {
        c(it)
    }
}
doSomething(['foo','bar']) { println it.toUpperCase() }
doSomething([1,2,3]) { println(2*it) }

Variants for SecondGenericType and ThirdGenericType exist for all FirstParam, SecondParam and ThirdParam type hints.

SimpleType

No

A type hint for which the type of closure parameters comes from the options string.

import groovy.transform.stc.SimpleType
public void doSomething(@ClosureParams(value=SimpleType,options=['java.lang.String','int']) Closure c) {
    c('foo',3)
}
doSomething { str, len ->
    assert str.length() == len
}

This type hint supports a single signature and each of the parameter is specified as a value of the options array using a fully-qualified type name or a primitive type.

MapEntryOrKeyValue

Yes

A dedicated type hint for closures that either work on a Map.Entry single parameter, or two parameters corresponding to the key and the value.

import groovy.transform.stc.MapEntryOrKeyValue
public <K,V> void doSomething(Map<K,V> map, @ClosureParams(MapEntryOrKeyValue) Closure c) {
    // ...
}
doSomething([a: 'A']) { k,v ->
    assert k.toUpperCase() == v.toUpperCase()
}
doSomething([abc: 3]) { e ->
    assert e.key.length() == e.value
}

This type hint requires that the first argument is a Map type, and infers the closure parameter types from the map actual key/value types.

FromAbstractTypeMethods

Yes

Infers closure parameter types from the abstract method of some type. A signature is inferred for each abstract method.

import groovy.transform.stc.FromAbstractTypeMethods
abstract class Foo {
    abstract void firstSignature(int x, int y)
    abstract void secondSignature(String str)
}
void doSomething(@ClosureParams(value=FromAbstractTypeMethods, options=["Foo"]) Closure cl) {
    // ...
}
doSomething { a, b -> a+b }
doSomething { s -> s.toUpperCase() }

If there are multiple signatures like in the example above, the type checker will only be able to infer the types of the arguments if the arity of each method is different. In the example above, firstSignature takes 2 arguments and secondSignature takes 1 argument, so the type checker can infer the argument types based on the number of arguments.

FromString

Yes

Infers the closure parameter types from the options argument. The options argument consists of an array of comma-separated non-primitive types. Each element of the array corresponds to a single signature, and each comma in an element separate parameters of the signature. In short, this is the most generic type hint, and each string of the options map is parsed as if it was a signature literal. While being very powerful, this type hint must be avoided if you can because it increases the compilation times due to the necessity of parsing the type signatures.

A single signature for a closure accepting a String:

import groovy.transform.stc.FromString
void doSomething(@ClosureParams(value=FromString, options=["String","String,Integer"]) Closure cl) {
    // ...
}
doSomething { s -> s.toUpperCase() }
doSomething { s,i -> s.toUpperCase()*i }

A polymorphic closure, accepting either a String or a String, Integer:

import groovy.transform.stc.FromString
void doSomething(@ClosureParams(value=FromString, options=["String","String,Integer"]) Closure cl) {
    // ...
}
doSomething { s -> s.toUpperCase() }
doSomething { s,i -> s.toUpperCase()*i }

A polymorphic closure, accepting either a T or a pair T,T:

import groovy.transform.stc.FromString
public <T> void doSomething(T e, @ClosureParams(value=FromString, options=["T","T,T"]) Closure cl) {
    // ...
}
doSomething('foo') { s -> s.toUpperCase() }
doSomething('foo') { s1,s2 -> assert s1.toUpperCase() == s2.toUpperCase() }
Even though you use FirstParam, SecondParam or ThirdParam as a type hint, it doesn’t strictly mean that the argument which will be passed to the closure will be the first (resp. second, third) argument of the method call. It only means that the type of the parameter of the closure will be the same as the type of the first (resp. second, third) argument of the method call.

In short, the lack of the @ClosureParams annotation on a method accepting a Closure will not fail compilation. If present (and it can be present in Java sources as well as Groovy sources), then the type checker has more information and can perform additional type inference. This makes this feature particularly interesting for framework developers.

@DelegatesTo

The @DelegatesTo annotation is used by the type checker to infer the type of the delegate. It allows the API designer to instruct the compiler what is the type of the delegate and the delegation strategy. The @DelegatesTo annotation is discussed in a specific section.

Static compilation
Dynamic vs static

In the type checking section, we have seen that Groovy provides optional type checking thanks to the @TypeChecked annotation. The type checker runs at compile time and performs a static analysis of dynamic code. The program will behave exactly the same whether type checking has been enabled or not. This means that the @TypeChecked annotation is neutral with regards to the semantics of a program. Even though it may be necessary to add type information in the sources so that the program is considered type safe, in the end, the semantics of the program are the same.

While this may sound fine, there is actually one issue with this: type checking of dynamic code, done at compile time, is by definition only correct if no runtime specific behavior occurs. For example, the following program passes type checking:

class Computer {
    int compute(String str) {
        str.length()
    }
    String compute(int x) {
        String.valueOf(x)
    }
}

@groovy.transform.TypeChecked
void test() {
    def computer = new Computer()
    computer.with {
        assert compute(compute('foobar')) =='6'
    }
}

There are two compute methods. One accepts a String and returns an int, the other accepts an int and returns a String. If you compile this, it is considered type safe: the inner compute('foobar') call will return an int, and calling compute on this int will in turn return a String.

Now, before calling test(), consider adding the following line:

Computer.metaClass.compute = { String str -> new Date() }

Using runtime metaprogramming, we’re actually modifying the behavior of the compute(String) method, so that instead of returning the length of the provided argument, it will return a Date. If you execute the program, it will fail at runtime. Since this line can be added from anywhere, in any thread, there’s absolutely no way for the type checker to statically make sure that no such thing happens. In short, the type checker is vulnerable to monkey patching. This is just one example, but this illustrates the concept that doing static analysis of a dynamic program is inherently wrong.

The Groovy language provides an alternative annotation to @TypeChecked which will actually make sure that the methods which are inferred as being called will effectively be called at runtime. This annotation turns the Groovy compiler into a static compiler, where all method calls are resolved at compile time and the generated bytecode makes sure that this happens: the annotation is @groovy.transform.CompileStatic.

The @CompileStatic annotation

The @CompileStatic annotation can be added anywhere the @TypeChecked annotation can be used, that is to say on a class or a method. It is not necessary to add both @TypeChecked and @CompileStatic, as @CompileStatic performs everything @TypeChecked does, but in addition triggers static compilation.

Let’s take the example which failed, but this time let’s replace the @TypeChecked annotation with @CompileStatic:

class Computer {
    int compute(String str) {
        str.length()
    }
    String compute(int x) {
        String.valueOf(x)
    }
}

@groovy.transform.CompileStatic
void test() {
    def computer = new Computer()
    computer.with {
        assert compute(compute('foobar')) =='6'
    }
}
Computer.metaClass.compute = { String str -> new Date() }
run()

This is the only difference. If we execute this program, this time, there is no runtime error. The test method became immune to monkey patching, because the compute methods which are called in its body are linked at compile time, so even if the metaclass of Computer changes, the program still behaves as expected by the type checker.

Key benefits

There are several benefits of using @CompileStatic on your code:

The performance improvements depend on the kind of program you are executing. If it is I/O bound, the difference between statically compiled code and dynamic code is barely noticeable. On highly CPU intensive code, since the bytecode which is generated is very close, if not equal, to the one that Java would produce for an equivalent program, the performance is greatly improved.

Using the invokedynamic version of Groovy, which is accessible to people using JDK 7 and above, the performance of the dynamic code should be very close to the performance of statically compiled code. Sometimes, it can even be faster! There is only one way to determine which version you should choose: measuring. The reason is that depending on your program and the JVM that you use, the performance can be significantly different. In particular, the invokedynamic version of Groovy is very sensitive to the JVM version in use.

1.6.7. Type checking extensions

Writing a type checking extension
Towards a smarter type checker

Despite being a dynamic language, Groovy can be used with a static type checker at compile time, enabled using the @TypeChecked annotation. In this mode, the compiler becomes more verbose and throws errors for, example, typos, non-existent methods,… This comes with a few limitations though, most of them coming from the fact that Groovy remains inherently a dynamic language. For example, you wouldn’t be able to use type checking on code that uses the markup builder:

def builder = new MarkupBuilder(out)
builder.html {
    head {
        // ...
    }
    body {
        p 'Hello, world!'
    }
}

In the previous example, none of the html, head, body or p methods exist. However if you execute the code, it works because Groovy uses dynamic dispatch and converts those method calls at runtime. In this builder, there’s no limitation about the number of tags that you can use, nor the attributes, which means there is no chance for a type checker to know about all the possible methods (tags) at compile time, unless you create a builder dedicated to HTML for example.

Groovy is a platform of choice when it comes to implement internal DSLs. The flexible syntax, combined with runtime and compile-time metaprogramming capabilities make Groovy an interesting choice because it allows the programmer to focus on the DSL rather than on tooling or implementation. Since Groovy DSLs are Groovy code, it’s easy to have IDE support without having to write a dedicated plugin for example.

In a lot of cases, DSL engines are written in Groovy (or Java) then user code is executed as scripts, meaning that you have some kind of wrapper on top of user logic. The wrapper may consist, for example, in a GroovyShell or GroovyScriptEngine that performs some tasks transparently before running the script (adding imports, applying AST transforms, extending a base script,…). Often, user written scripts come to production without testing because the DSL logic comes to a point where any user may write code using the DSL syntax. In the end, a user may just ignore that what he writes is actually code. This adds some challenges for the DSL implementer, such as securing execution of user code or, in this case, early reporting of errors.

For example, imagine a DSL which goal is to drive a rover on Mars remotely. Sending a message to the rover takes around 15 minutes. If the rover executes the script and fails with an error (say a typo), you have two problems:

  • first, feedback comes only after 30 minutes (the time needed for the rover to get the script and the time needed to receive the error)

  • second, some portion of the script has been executed and you may have to change the fixed script significantly (implying that you need to know the current state of the rover…)

Type checking extensions is a mechanism that will allow the developer of a DSL engine to make those scripts safer by applying the same kind of checks that static type checking allows on regular groovy classes.

The principle, here, is to fail early, that is to say fail compilation of scripts as soon as possible, and if possible provide feedback to the user (including nice error messages).

In short, the idea behind type checking extensions is to make the compiler aware of all the runtime metaprogramming tricks that the DSL uses, so that scripts can benefit the same level of compile-time checks as a verbose statically compiled code would have. We will see that you can go even further by performing checks that a normal type checker wouldn’t do, delivering powerful compile-time checks for your users.

The extensions attribute

The @TypeChecked annotation supports an attribute named extensions. This parameter takes an array of strings corresponding to a list of type checking extensions scripts. Those scripts are found at compile time on classpath. For example, you would write:

@TypeChecked(extensions='/path/to/myextension.groovy')
void foo() { ...}

In that case, the foo methods would be type checked with the rules of the normal type checker completed by those found in the myextension.groovy script. Note that while internally the type checker supports multiple mechanisms to implement type checking extensions (including plain old java code), the recommended way is to use those type checking extension scripts.

A DSL for type checking

The idea behind type checking extensions is to use a DSL to extend the type checker capabilities. This DSL allows you to hook into the compilation process, more specifically the type checking phase, using an "event-driven" API. For example, when the type checker enters a method body, it throws a beforeVisitMethod event that the extension can react to:

beforeVisitMethod { methodNode ->
 println "Entering ${methodNode.name}"
}

Imagine that you have this rover DSL at hand. A user would write:

robot.move 100

If you have a class defined as such:

class Robot {
    Robot move(int qt) { this }
}

The script can be type checked before being executed using the following script:

def config = new CompilerConfiguration()
config.addCompilationCustomizers(
    new ASTTransformationCustomizer(TypeChecked)            (1)
)
def shell = new GroovyShell(config)                         (2)
def robot = new Robot()
shell.setVariable('robot', robot)
shell.evaluate(script)                                      (3)
1 a compiler configuration adds the @TypeChecked annotation to all classes
2 use the configuration in a GroovyShell
3 so that scripts compiled using the shell are compiled with @TypeChecked without the user having to add it explicitly

Using the compiler configuration above, we can apply @TypeChecked transparently to the script. In that case, it will fail at compile time:

[Static type checking] - The variable [robot] is undeclared.

Now, we will slightly update the configuration to include the ``extensions'' parameter:

config.addCompilationCustomizers(
    new ASTTransformationCustomizer(
        TypeChecked,
        extensions:['robotextension.groovy'])
)

Then add the following to your classpath:

robotextension.groovy
unresolvedVariable { var ->
    if ('robot'==var.name) {
        storeType(var, classNodeFor(Robot))
        handled = true
    }
}

Here, we’re telling the compiler that if an unresolved variable is found and that the name of the variable is robot, then we can make sure that the type of this variable is Robot.

Type checking extensions API
AST

The type checking API is a low level API, dealing with the Abstract Syntax Tree. You will have to know your AST well to develop extensions, even if the DSL makes it much easier than just dealing with AST code from plain Java or Groovy.

Events

The type checker sends the following events, to which an extension script can react:

Event name

setup

Called When

Called after the type checker finished initialization

Arguments

none

Usage

setup {
    // this is called before anything else
}

Can be used to perform setup of your extension

Event name

finish

Called When

Called after the type checker completed type checking

Arguments

none

Usage

finish {
    // this is after completion
    // of all type checking
}

Can be used to perform additional checks after the type checker has finished its job.

Event name

unresolvedVariable

Called When

Called when the type checker finds an unresolved variable

Arguments

VariableExpression var

Usage

unresolvedVariable { var ->
    if ('people' == var.name) {
        storeType(var, classNodeFor(List))
        handled = true
    }
}

Allows the developer to help the type checker with user-injected variables.

Event name

unresolvedProperty

Called When

Called when the type checker cannot find a property on the receiver

Arguments

PropertyExpression pexp

Usage

unresolvedProperty { pexp ->
    if ('longueur'==pexp.propertyAsString &&
        getType(pexp.objectExpression)==classNodeFor(String)) {
        storeType(pexp,classNodeFor(int))
        handled = true
    }
}

Allows the developer to handle "dynamic" properties

Event name

unresolvedAttribute

Called When

Called when the type checker cannot find an attribute on the receiver

Arguments

AttributeExpression aex

Usage

unresolvedAttribute { aex ->
    if (getType(aex.objectExpression)==classNodeFor(String)) {
        storeType(aex,classNodeFor(String))
        handled = true
    }
}

Allows the developer to handle missing attributes

Event name

beforeMethodCall

Called When

Called before the type checker starts type checking a method call

Arguments

MethodCall call

Usage

beforeMethodCall { call ->
    if (isMethodCallExpression(call)
            && call.methodAsString=='toUpperCase') {
        addStaticTypeError('Not allowed',call)
        handled = true
    }
}

Allows you to intercept method calls before the type checker performs its own checks. This is useful if you want to replace the default type checking with a custom one for a limited scope. In that case, you must set the handled flag to true, so that the type checker skips its own checks.

Event name

afterMethodCall

Called When

Called once the type checker has finished type checking a method call

Arguments

MethodCall call

Usage

afterMethodCall { call ->
    if (getTargetMethod(call).name=='toUpperCase') {
        addStaticTypeError('Not allowed',call)
        handled = true
    }
}

Allow you to perform additional checks after the type checker has done its own checks. This is in particular useful if you want to perform the standard type checking tests but also want to ensure additional type safety, for example checking the arguments against each other.Note that afterMethodCall is called even if you did beforeMethodCall and set the handled flag to true.

Event name

onMethodSelection

Called When

Called by the type checker when it finds a method appropriate for a method call

Arguments

Expression expr, MethodNode node

Usage

onMethodSelection { expr, node ->
    if (node.declaringClass.name == 'java.lang.String') {
        // calling a method on 'String'
        // let’s perform additional checks!
        if (++count>2) {
            addStaticTypeError("You can use only 2 calls on String in your source code",expr)
        }
    }
}

The type checker works by inferring argument types of a method call, then chooses a target method. If it finds one that corresponds, then it triggers this event. It is for example interesting if you want to react on a specific method call, such as entering the scope of a method that takes a closure as argument (as in builders).Please note that this event may be thrown for various types of expressions, not only method calls (binary expressions for example).

Event name

methodNotFound

Called When

Called by the type checker when it fails to find an appropriate method for a method call

Arguments

ClassNode receiver, String name, ArgumentListExpression argList, ClassNode[] argTypes,MethodCall call

Usage

methodNotFound { receiver, name, argList, argTypes, call ->
    // receiver is the inferred type of the receiver
    // name is the name of the called method
    // argList is the list of arguments the method was called with
    // argTypes is the array of inferred types for each argument
    // call is the method call for which we couldn’t find a target method
    if (receiver==classNodeFor(String)
            && name=='longueur'
            && argList.size()==0) {
        handled = true
        return newMethod('longueur', classNodeFor(String))
    }
}

Unlike onMethodSelection, this event is sent when the type checker cannot find a target method for a method call (instance or static). It gives you the chance to intercept the error before it is sent to the user, but also set the target method.For this, you need to return a list of MethodNode. In most situations, you would either return: an empty list, meaning that you didn’t find a corresponding method, a list with exactly one element, saying that there’s no doubt about the target methodIf you return more than one MethodNode, then the compiler would throw an error to the user stating that the method call is ambiguous, listing the possible methods.For convenience, if you want to return only one method, you are allowed to return it directly instead of wrapping it into a list.

Event name

beforeVisitMethod

Called When

Called by the type checker before type checking a method body

Arguments

MethodNode node

Usage

beforeVisitMethod { methodNode ->
    // tell the type checker we will handle the body by ourselves
    handled = methodNode.name.startsWith('skip')
}

The type checker will call this method before starting to type check a method body. If you want, for example, to perform type checking by yourself instead of letting the type checker do it, you have to set the handled flag to true.This event can also be used to help defining the scope of your extension (for example, applying it only if you are inside method foo).

Event name

afterVisitMethod

Called When

Called by the type checker after type checking a method body

Arguments

MethodNode node

Usage

afterVisitMethod { methodNode ->
    scopeExit {
        if (methods>2) {
            addStaticTypeError("Method ${methodNode.name} contains more than 2 method calls", methodNode)
        }
    }
}

Gives you the opportunity to perform additional checks after a method body is visited by the type checker. This is useful if you collect information, for example, and want to perform additional checks once everything has been collected.

Event name

beforeVisitClass

Called When

Called by the type checker before type checking a class

Arguments

ClassNode node

Usage

beforeVisitClass { ClassNode classNode ->
    def name = classNode.nameWithoutPackage
    if (!(name[0] in 'A'..'Z')) {
        addStaticTypeError("Class '${name}' doesn't start with an uppercase letter",classNode)
    }
}

If a class is type checked, then before visiting the class, this event will be sent. It is also the case for inner classes defined inside a class annotated with @TypeChecked. It can help you define the scope of your extension, or you can even totally replace the visit of the type checker with a custom type checking implementation. For that, you would have to set the handled flag to true

Event name

afterVisitClass

Called When

Called by the type checker after having finished the visit of a type checked class

Arguments

ClassNode node

Usage

afterVisitClass { ClassNode classNode ->
    def name = classNode.nameWithoutPackage
    if (!(name[0] in 'A'..'Z')) {
        addStaticTypeError("Class '${name}' doesn't start with an uppercase letter",classNode)
    }
}

Called for every class being type checked after the type checker finished its work. This includes classes annotated with @TypeChecked and any inner/anonymous class defined in the same class with is not skipped.

Event name

incompatibleAssignment

Called When

Called when the type checker thinks that an assignment is incorrect, meaning that the right hand side of an assignment is incompatible with the left hand side

Arguments

ClassNode lhsType, ClassNode rhsType,  Expression assignment

Usage

incompatibleAssignment { lhsType, rhsType, expr ->
    if (isBinaryExpression(expr) && isAssignment(expr.operation.type)) {
        if (lhsType==classNodeFor(int) && rhsType==classNodeFor(Closure)) {
            handled = true
        }
    }
}

Gives the developer the ability to handle incorrect assignments. This is for example useful if a class overrides setProperty, because in that case it is possible that assigning a variable of one type to a property of another type is handled through that runtime mechanism. In that case, you can help the type checker just by telling it that the assignment is valid (using handled set to true).

Event name

ambiguousMethods

Called When

Called when the type checker cannot choose between several candidate methods

Arguments

List<MethodNode> methods,  Expression origin

Usage

ambiguousMethods { methods, origin ->
    // choose the method which has an Integer as parameter type
    methods.find { it.parameters.any { it.type == classNodeFor(Integer) } }
}

Gives the developer the ability to handle incorrect assignments. This is for example useful if a class overrides setProperty, because in that case it is possible that assigning a variable of one type to a property of another type is handled through that runtime mechanism. In that case, you can help the type checker just by telling it that the assignment is valid (using handled set to true).

Of course, an extension script may consist of several blocks, and you can have multiple blocks responding to the same event. This makes the DSL look nicer and easier to write. However, reacting to events is far from sufficient. If you know you can react to events, you also need to deal with the errors, which implies several helper methods that will make things easier.

Working with extensions
Support classes

The DSL relies on a support class called org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport . This class itself extends org.codehaus.groovy.transform.stc.TypeCheckingExtension . Those two classes define a number of helper methods that will make working with the AST easier, especially regarding type checking. One interesting thing to know is that you have access to the type checker. This means that you can programmatically call methods of the type checker, including those that allow you to throw compilation errors.

The extension script delegates to the org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport class, meaning that you have direct access to the following variables:

The type checking context contains a lot of information that is useful in context for the type checker. For example, the current stack of enclosing method calls, binary expressions, closures, … This information is in particular important if you have to know where you are when an error occurs and that you want to handle it.

Class nodes

Handling class nodes is something that needs particular attention when you work with a type checking extension. Compilation works with an abstract syntax tree (AST) and the tree may not be complete when you are type checking a class. This also means that when you refer to types, you must not use class literals such as String or HashSet, but to class nodes representing those types. This requires a certain level of abstraction and understanding how Groovy deals with class nodes. To make things easier, Groovy supplies several helper methods to deal with class nodes. For example, if you want to say "the type for String", you can write:

assert classNodeFor(String) instanceof ClassNode

You would also note that there is a variant of classNodeFor that takes a String as an argument, instead of a Class. In general, you should not use that one, because it would create a class node for which the name is String, but without any method, any property, … defined on it. The first version returns a class node that is resolved but the second one returns one that is not. So the latter should be reserved for very special cases.

The second problem that you might encounter is referencing a type which is not yet compiled. This may happen more often than you think. For example, when you compile a set of files together. In that case, if you want to say "that variable is of type Foo" but Foo is not yet compiled, you can still refer to the Foo class node using lookupClassNodeFor:

assert lookupClassNodeFor('Foo') instanceof ClassNode
Helping the type checker

Say that you know that variable foo is of type Foo and you want to tell the type checker about it. Then you can use the storeType method, which takes two arguments: the first one is the node for which you want to store the type and the second one is the type of the node. If you look at the implementation of storeType, you would see that it delegates to the type checker equivalent method, which itself does a lot of work to store node metadata. You would also see that storing the type is not limited to variables: you can set the type of any expression.

Likewise, getting the type of an AST node is just a matter of calling getType on that node. This would in general be what you want, but there’s something that you must understand:

  • getType returns the inferred type of an expression. This means that it will not return, for a variable declared of type Object the class node for Object, but the inferred type of this variable at this point of the code (flow typing)

  • if you want to access the origin type of a variable (or field/parameter), then you must call the appropriate method on the AST node

Throwing an error

To throw a type checking error, you only have to call the addStaticTypeError method which takes two arguments:

  • message which is a string that will be displayed to the end user

  • an AST node responsible for the error. It’s better to provide the best suiting AST node because it will be used to retrieve the line and column numbers

isXXXExpression

It is often required to know the type of an AST node. For readability, the DSL provides a special isXXXExpression method that will delegate to x instance of XXXExpression. For example, instead of writing:

if (node instanceof BinaryExpression) {
   ...
}

which requires you to import the BinaryExpression class, you can just write:

if (isBinaryExpression(node)) {
   ...
}
Virtual methods

When you perform type checking of dynamic code, you may often face the case when you know that a method call is valid but there is no "real" method behind it. As an example, take the Grails dynamic finders. You can have a method call consisting of a method named findByName(…). As there’s no findByName method defined in the bean, the type checker would complain. Yet, you would know that this method wouldn’t fail at runtime, and you can even tell what is the return type of this method. For this case, the DSL supports two special constructs that consist of phantom methods. This means that you will return a method node that doesn’t really exist but is defined in the context of type checking. Three methods exist:

  • newMethod(String name, Class returnType)

  • newMethod(String name, ClassNode returnType)

  • newMethod(String name, Callable<ClassNode> return Type)

All three variants do the same: they create a new method node which name is the supplied name and define the return type of this method. Moreover, the type checker would add those methods in the generatedMethods list (see isGenerated below). The reason why we only set a name and a return type is that it is only what you need in 90% of the cases. For example, in the findByName example upper, the only thing you need to know is that findByName wouldn’t fail at runtime, and that it returns a domain class. The Callable version of return type is interesting because it defers the computation of the return type when the type checker actually needs it. This is interesting because in some circumstances, you may not know the actual return type when the type checker demands it, so you can use a closure that will be called each time getReturnType is called by the type checker on this method node. If you combine this with deferred checks, you can achieve pretty complex type checking including handling of forward references.

newMethod(name) {
    // each time getReturnType on this method node will be called, this closure will be called!
    println 'Type checker called me!'
    lookupClassNodeFor(Foo) // return type
}

Should you need more than the name and return type, you can always create a new MethodNode by yourself.

Scoping

Scoping is very important in DSL type checking and is one of the reasons why we couldn’t use a pointcut based approach to DSL type checking. Basically, you must be able to define very precisely when your extension applies and when it does not. Moreover, you must be able to handle situations that a regular type checker would not be able to handle, such as forward references:

point a(1,1)
line a,b // b is referenced afterwards!
point b(5,2)

Say for example that you want to handle a builder:

builder.foo {
   bar
   baz(bar)
}

Your extension, then, should only be active once you’ve entered the foo method, and inactive outside of this scope. But you could have complex situations like multiple builders in the same file or embedded builders (builders in builders). While you should not try to fix all this from start (you must accept limitations to type checking), the type checker does offer a nice mechanism to handle this: a scoping stack, using the newScope and scopeExit methods.

  • newScope creates a new scope and puts it on top of the stack

  • scopeExits pops a scope from the stack

A scope consists of:

  • a parent scope

  • a map of custom data

If you want to look at the implementation, it’s simply a LinkedHashMap (org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingScope), but it’s quite powerful. For example, you can use such a scope to store a list of closures to be executed when you exit the scope. This is how you would handle forward references: 

def scope = newScope()
scope.secondPassChecks = []
//...
scope.secondPassChecks << { println 'executed later' }
// ...
scopeExit {
    secondPassChecks*.run() // execute deferred checks
}

That is to say, that if at some point you are not able to determine the type of an expression, or that you are not able to check at this point that an assignment is valid or not, you can still make the check later… This is a very powerful feature. Now, newScope and scopeExit provide some interesting syntactic sugar:

newScope {
    secondPassChecks = []
}

At anytime in the DSL, you can access the current scope using getCurrentScope() or more simply currentScope:

//...
currentScope.secondPassChecks << { println 'executed later' }
// ...

The general schema would then be:

  • determine a pointcut where you push a new scope on stack and initialize custom variables within this scope

  • using the various events, you can use the information stored in your custom scope to perform checks, defer checks,…

  • determine a pointcut where you exit the scope, call scopeExit and eventually perform additional checks

Other useful methods

For the complete list of helper methods, please refer to the org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport and  org.codehaus.groovy.transform.stc.TypeCheckingExtension classes. However, take special attention to those methods:

  • isDynamic: takes a VariableExpression as argument and returns true if the variable is a DynamicExpression, which means, in a script, that it wasn’t defined using a type or def.

  • isGenerated: takes a MethodNode as an argument and tells if the method is one that was generated by the type checker extension using the newMethod method

  • isAnnotatedBy: takes an AST node and a Class (or ClassNode), and tells if the node is annotated with this class. For example: isAnnotatedBy(node, NotNull)

  • getTargetMethod: takes a method call as argument and returns the MethodNode that the type checker has determined for it

  • delegatesTo: emulates the behaviour of the @DelegatesTo annotation. It allows you to tell that the argument will delegate to a specific type (you can also specify the delegation strategy)

Advanced type checking extensions
Precompiled type checking extensions

All the examples above use type checking scripts. They are found in source form in classpath, meaning that:

  • a Groovy source file, corresponding to the type checking extension, is available on compilation classpath

  • this file is compiled by the Groovy compiler for each source unit being compiled (often, a source unit corresponds to a single file)

It is a very convenient way to develop type checking extensions, however it implies a slower compilation phase, because of the compilation of the extension itself for each file being compiled. For those reasons, it can be practical to rely on a precompiled extension. You have two options to do this:

  • write the extension in Groovy, compile it, then use a reference to the extension class instead of the source

  • write the extension in Java, compile it, then use a reference to the extension class

Writing a type checking extension in Groovy is the easiest path. Basically, the idea is that the type checking extension script becomes the body of the main method of a type checking extension class, as illustrated here:

import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport

class PrecompiledExtension extends GroovyTypeCheckingExtensionSupport.TypeCheckingDSL {     (1)
    @Override
    Object run() {                                                                          (2)
        unresolvedVariable { var ->
            if ('robot'==var.name) {
                storeType(var, classNodeFor(Robot))                                         (3)
                handled = true
            }
        }
    }
}
1 extending the TypeCheckingDSL class is the easiest
2 then the extension code needs to go inside the run method
3 and you can use the very same events as an extension written in source form

Setting up the extension is very similar to using a source form extension:

config.addCompilationCustomizers(
    new ASTTransformationCustomizer(
        TypeChecked,
        extensions:['typing.PrecompiledExtension'])
)

The difference is that instead of using a path in classpath, you just specify the fully qualified class name of the precompiled extension.

In case you really want to write an extension in Java, then you will not benefit from the type checking extension DSL. The extension above can be rewritten in Java this way:

import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension;


import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;

public class PrecompiledJavaExtension extends AbstractTypeCheckingExtension {                   (1)

    public PrecompiledJavaExtension(final StaticTypeCheckingVisitor typeCheckingVisitor) {
        super(typeCheckingVisitor);
    }

    @Override
    public boolean handleUnresolvedVariableExpression(final VariableExpression vexp) {          (2)
        if ("robot".equals(vexp.getName())) {
            storeType(vexp, ClassHelper.make(Robot.class));
            setHandled(true);
            return true;
        }
        return false;
    }

}
1 extend the AbstractTypeCheckingExtension class
2 then override the handleXXX methods as required
Using @Grab in a type checking extension

It is totally possible to use the @Grab annotation in a type checking extension. This means you can include libraries that would only be available at compile time. In that case, you must understand that you would increase the time of compilation significantly (at least, the first time it grabs the dependencies).

Sharing or packaging type checking extensions

A type checking extension is just a script that need to be on classpath. As such, you can share it as is, or bundle it in a jar file that would be added to classpath.

Global type checking extensions

While you can configure the compiler to transparently add type checking extensions to your script, there is currently no way to apply an extension transparently just by having it on classpath.

Type checking extensions and @CompileStatic

Type checking extensions are used with @TypeChecked but can also be used with @CompileStatic. However, you must be aware that:

  • a type checking extension used with @CompileStatic will in general not be sufficient to let the compiler know how to generate statically compilable code from "unsafe" code

  • it is possible to use a type checking extension with @CompileStatic just to enhance type checking, that is to say introduce more compilation errors, without actually dealing with dynamic code

Let’s explain the first point, which is that even if you use an extension, the compiler will not know how to compile your code statically: technically, even if you tell the type checker what is the type of a dynamic variable, for example, it would not know how to compile it. Is it getBinding('foo'), getProperty('foo'), delegate.getFoo(),…? There’s absolutely no direct way to tell the static compiler how to compile such code even if you use a type checking extension (that would, again, only give hints about the type).

One possible solution for this particular example is to instruct the compiler to use mixed mode compilation. The more advanced one is to use AST transformations during type checking but it is far more complex.

Type checking extensions allow you to help the type checker where it fails, but it also allow you to fail where it doesn’t. In that context, it makes sense to support extensions for @CompileStatic too. Imagine an extension that is capable of type checking SQL queries. In that case, the extension would be valid in both dynamic and static context, because without the extension, the code would still pass.

Mixed mode compilation

In the previous section, we highlighted the fact that you can activate type checking extensions with @CompileStatic. In that context, the type checker would not complain anymore about some unresolved variables or unknown method calls, but it would still wouldn’t know how to compile them statically.

Mixed mode compilation offers a third way, which is to instruct the compiler that whenever an unresolved variable or method call is found, then it should fall back to a dynamic mode. This is possible thanks to type checking extensions and a special makeDynamic call.

To illustrate this, let’s come back to the Robot example:

robot.move 100

And let’s try to activate our type checking extension using @CompileStatic instead of @TypeChecked:

def config = new CompilerConfiguration()
config.addCompilationCustomizers(
    new ASTTransformationCustomizer(
        CompileStatic,                                      (1)
        extensions:['robotextension.groovy'])               (2)
)
def shell = new GroovyShell(config)
def robot = new Robot()
shell.setVariable('robot', robot)
shell.evaluate(script)
1 Apply @CompileStatic transparently
2 Activate the type checking extension

The script will run fine because the static compiler is told about the type of the robot variable, so it is capable of making a direct call to move. But before that, how did the compiler know how to get the robot variable? In fact by default, in a type checking extension, setting handled=true on an unresolved variable will automatically trigger a dynamic resolution, so in this case you don’t have anything special to make the compiler use a mixed mode. However, let’s slightly update our example, starting from the robot script:

move 100

Here you can notice that there is no reference to robot anymore. Our extension will not help then because we will not be able to instruct the compiler that move is done on a Robot instance. This example of code can be executed in a totally dynamic way thanks to the help of a groovy.util.DelegatingScript:

def config = new CompilerConfiguration()
config.scriptBaseClass = 'groovy.util.DelegatingScript'     (1)
def shell = new GroovyShell(config)
def runner = shell.parse(script)                            (2)
runner.setDelegate(new Robot())                             (3)
runner.run()                                                (4)
1 we configure the compiler to use a DelegatingScript as the base class
2 the script source needs to be parsed and will return an instance of DelegatingScript
3 we can then call setDelegate to use a Robot as the delegate of the script
4 then execute the script. move will be directly executed on the delegate

If we want this to pass with @CompileStatic, we have to use a type checking extension, so let’s update our configuration:

config.addCompilationCustomizers(
    new ASTTransformationCustomizer(
        CompileStatic,                                      (1)
        extensions:['robotextension2.groovy'])              (2)
)
1 apply @CompileStatic transparently
2 use an alternate type checking extension meant to recognize the call to move

Then in the previous section we have learnt how to deal with unrecognized method calls, so we are able to write this extension:

robotextension2.groovy
methodNotFound { receiver, name, argList, argTypes, call ->
    if (isMethodCallExpression(call)                        (1)
        && call.implicitThis                                (2)
        && 'move'==name                                     (3)
        && argTypes.length==1                               (4)
        && argTypes[0] == classNodeFor(int)                 (5)
    ) {
        handled = true                                      (6)
        newMethod('move', classNodeFor(Robot))              (7)
    }
}
1 if the call is a method call (not a static method call)
2 that this call is made on "implicit this" (no explicit this.)
3 that the method being called is move
4 and that the call is done with a single argument
5 and that argument is of type int
6 then tell the type checker that the call is valid
7 and that the return type of the call is Robot

If you try to execute this code, then you could be surprised that it actually fails at runtime:

java.lang.NoSuchMethodError: java.lang.Object.move()Ltyping/Robot;

The reason is very simple: while the type checking extension is sufficient for @TypeChecked, which does not involve static compilation, it is not enough for @CompileStatic which requires additional information. In this case, you told the compiler that the method existed, but you didn’t explain to it what method it is in reality, and what is the receiver of the message (the delegate).

Fixing this is very easy and just implies replacing the newMethod call with something else:

robotextension3.groovy
methodNotFound { receiver, name, argList, argTypes, call ->
    if (isMethodCallExpression(call)
        && call.implicitThis
        && 'move'==name
        && argTypes.length==1
        && argTypes[0] == classNodeFor(int)
    ) {
        makeDynamic(call, classNodeFor(Robot))              (1)
    }
}
1 tell the compiler that the call should be make dynamic

The makeDynamic call does 3 things:

  • it returns a virtual method just like newMethod

  • automatically sets the handled flag to true for you

  • but also marks the call to be done dynamically

So when the compiler will have to generate bytecode for the call to move, since it is now marked as a dynamic call, it will fallback to the dynamic compiler and let it handle the call. And since the extension tells us that the return type of the dynamic call is a Robot, subsequent calls will be done statically!

Some would wonder why the static compiler doesn’t do this by default without an extension. It is a design decision:

  • if the code is statically compiled, we normally want type safety and best performance

  • so if unrecognized variables/method calls are made dynamic, you loose type safety, but also all support for typos at compile time!

In short, if you want to have mixed mode compilation, it has to be explicit, through a type checking extension, so that the compiler, and the designer of the DSL, are totally aware of what they are doing.

makeDynamic can be used on 3 kind of AST nodes:

  • a method node (MethodNode)

  • a variable (VariableExpression)

  • a property expression (PropertyExpression)

If that is not enough, then it means that static compilation cannot be done directly and that you have to rely on AST transformations.

Transforming the AST in an extension

Type checking extensions look very attractive from an AST transformation design point of view: extensions have access to context like inferred types, which is often nice to have. And an extension has a direct access to the abstract syntax tree. Since you have access to the AST, there is nothing in theory that prevents you from modifying the AST. However, we do not recommend you to do so, unless you are an advanced AST transformation designer and well aware of the compiler internals:

  • First of all, you would explicitly break the contract of type checking, which is to annotate, and only annotate the AST. Type checking should not modify the AST tree because you wouldn’t be able to guarantee anymore that code without the @TypeChecked annotation behaves the same without the annotation.

  • If your extension is meant to work with @CompileStatic, then you can modify the AST because this is indeed what @CompileStatic will eventually do. Static compilation doesn’t guarantee the same semantics at dynamic Groovy so there is effectively a difference between code compiled with @CompileStatic and code compiled with @TypeChecked. It’s up to you to choose whatever strategy you want to update the AST, but probably using an AST transformation that runs before type checking is easier.

  • if you cannot rely on a transformation that kicks in before the type checker, then you must be very careful

The type checking phase is the last phase running in the compiler before bytecode generation. All other AST transformations run before that and the compiler does a very good job at "fixing" incorrect AST generated before the type checking phase. As soon as you perform a transformation during type checking, for example directly in a type checking extension, then you have to do all this work of generating a 100% compiler compliant abstract syntax tree by yourself, which can easily become complex. That’s why we do not recommend to go that way if you are beginning with type checking extensions and AST transformations.
Examples

Examples of real life type checking extensions are easy to find. You can download the source code for Groovy and take a look at the TypeCheckingExtensionsTest class which is linked to various extension scripts.

An example of a complex type checking extension can be found in the Markup Template Engine source code: this template engine relies on a type checking extension and AST transformations to transform templates into fully statically compiled code. Sources for this can be found here.

2. Tools

2.1. Running Groovy from the commandline

2.1.1. groovy, the Groovy command

groovy invokes the Groovy command line processor. It allows you to run inline Groovy expressions, and scripts, tests or application within groovy files. It plays a similar role to java in the Java world but handles inline scripts and rather than invoking class files, it is normally called with scripts and will automatically call the Groovy compiler as needed.

The easiest way to run a Groovy script, test or application is to run the following command at your shell prompt:

> groovy MyScript.groovy

The .groovy part is optional. The groovy command supports a number of command line switches:

Short version Long version Description Example

-v

--version

display the Groovy and JVM versions

groovy -v

-a

--autosplit <splitPattern>

split lines using splitPattern (default '\s') using implicit 'split' variable

-b

--basescript <class>

Base class name for scripts (must derive from Script)

-c

--encoding <charset>

specify the encoding of the files

-cp <path>

-classpath <path>
--classpath <path>

Specify the compilation classpath. Must be the first argument.

groovy -cp lib/dep.jar MyScript

--configscript <path>

Advanced compiler configuration script

groovy --configscript config/config.groovy src/Person.groovy

-D

--define <name=value>

define a system property

-d

--debug

debug mode will print out full stack traces

--disableopt <optlist>

disables one or all optimization elements.
optlist can be a comma separated list with the elements:
all (disables all optimizations),
int (disable any int based optimizations)

-e <script>

specify an inline command line script

groovy -e "println new Date()"

-h

--help

Displays usage information for the command line groovy command

groovy --help

-i <extension>

modify files in place; create backup if extension is given (e.g. '.bak')

--indy

Enables invokedynamic support. Requires Java 7+

groovy --indy Person.groovy

-l <port>

listen on a port and process inbound lines (default: 1960)

-n

process files line by line using implicit 'line' variable

-p

process files line by line and print result (see also -n)

2.2. Compiling Groovy

2.2.1. groovyc, the Groovy compiler

groovyc is the Groovy compiler command line tool. It allows you to compile Groovy sources into bytecode. It plays the same role as javac in the Java world. The easiest way to compile a Groovy script or class is to run the following command:

groovyc MyClass.groovy

This will produce a MyClass.class file (as well as other .class files depending on the contents of the source). groovyc supports a number of command line switches:

Short version Long version Description Example

-Fflag

Flags to be passed to javac if joint compilation is enabled

groovyc -j -Fnowarn A.groovy B.java

-cp

-classpath, --classpath

Specify the compilation classpath. Must be the first argument.

groovyc -cp lib/dep.jar MyClass.groovy

--sourcepath*

Directory where to find source files

groovyc -sourcepath src script.groovy

--temp

Temporary directory for the compiler

--encoding

Encoding of the source files

groovyc -encoding utf-8 script.groovy

--help

Displays help for the command line groovyc tool

groovyc --help

-v

--version

Displays the compiler version

groovyc -v

-e

--exception

Displays the stack trace in case of compilation error

groovyc -e script.groovy

-j

--jointCompilation*

Enables joint compilation

groovyc -j A.groovy B.java

-b

--basescript

Base class name for scripts (must derive from Script)

-indy

--indy

Enables invokedynamic support. Requires Java 7+

groovyc --indy Person.groovy

--configscript

Advanced compiler configuration script

groovyc --configscript config/config.groovy src/Person.groovy

-Jproperty=value

Properties to be passed to javac if joint compilation is enabled

groovyc -j -Jtarget=1.5 -Jsource=1.5 A.groovy B.java

Notes:

  • sourcepath is not used anymore. Specifying this parameter will have no effect on compilation.

  • for a full description of joint compilation, see the joint compilation section.

2.2.2. Ant task

<groovyc>
Description

Compiles Groovy source files and, if joint compilation option is used, Java source files.

Required taskdef

Assuming groovy-all-VERSION.jar is in my.classpath you will need to declare this task at some point in the build.xml prior to the groovyc task being invoked.

<taskdef name="groovyc"
         classname="org.codehaus.groovy.ant.Groovyc"
         classpathref="my.classpath"/>
<groovyc> Attributes
Attribute Description Required

configscript

Set the configuration file used to customize the compilation configuration.

No

srcdir

Location of the Groovy (and possibly Java) source files.

Yes

destdir

Location to store the class files.

Yes

classpath

The classpath to use.

No

classpathref

The classpath to use given as a path references.

No

sourcepath

The sourcepath to use.

No

sourcepathref

The sourcepath to use given as a path reference.

No

encoding

Encoding of source files.

No

verbose

Asks the compiler for verbose output; defaults to no.

No

includeAntRuntime

Whether to include the Ant run-time libraries in the classpath; defaults to yes.

No

includeJavaRuntime

Whether to include the default run-time libraries from the executing VM in the classpath; defaults to no.

No

fork

Whether to execute groovyc using a spawned instance of the JVM; defaults to no.

No

memoryInitialSize

The initial size of the memory for the underlying VM, if using fork mode; ignored otherwise. Defaults to the standard VM memory setting. (Examples: 83886080, 81920k, or 80m)

No

memoryMaximumSize

The maximum size of the memory for the underlying VM, if using fork mode; ignored otherwise. Defaults to the standard VM memory setting. (Examples: 83886080, 81920k, or 80m)

No

failonerror

Indicates whether compilation errors will fail the build; defaults to true.

No

listfiles

Indicates whether the source files to be compiled will be listed; defaults to no.

No

stacktrace

if true each compile error message will contain a stacktrace

No

indy

Enable compilation with the ``invoke dynamic'' support when using Groovy 2.0 and beyond and running on JDK 7

No

scriptBaseClass

Sets the base class for Groovy scripts

No

stubdir

Set the stub directory into which the Java source stub files should be generated. The directory need not exist and will not be deleted automatically - though its contents will be cleared unless 'keepStubs' is true. Ignored when forked.

No

keepStubs

Set the keepStubs flag. Defaults to false. Set to true for debugging. Ignored when forked.

No

forceLookupUnnamedFiles

The Groovyc Ant task is frequently used in the context of a build system that knows the complete list of source files to be compiled. In such a context, it is wasteful for the Groovy compiler to go searching the classpath when looking for source files and hence by default the Groovyc Ant task calls the compiler in a special mode with such searching turned off. If you wish the compiler to search for source files then you need to set this flag to true. Defaults to false.

No

Example:

<groovyc srcdir="src" destdir="target/classes">
</groovyc>
<groovyc> Nested Elements
element kind Required Replaces Attribute

javac

javac task

No

jointCompilationOptions

src

a path structure

Yes (unless srcdir is used)

srcdir

classpath

a path structure

No

classpath

Notes:

  • For path structures see for example http://ant.apache.org/manual/using.html#path

  • For usages of the javac task see http://ant.apache.org/manual/CoreTasks/javac.html

  • The nested javac task behaves more or less as documented for the top-level javac task. srcdir, destdir, classpath, encoding for the nested javac task are taken from the enclosing groovyc task. If these attributes are specified then they are added, they do not replace. In fact, you should not attempt to overwrite the destination. Other attributes and nested elements are unaffected, for example fork, memoryMaximumSize, etc. may be used freely.

Joint Compilation

Joint compilation is enabled by using an embedded javac element, as shown in the following example:

<groovyc srcdir="${testSourceDirectory}" destdir="${testClassesDirectory}">
  <classpath>
    <pathelement path="${mainClassesDirectory}"/>
    <pathelement path="${testClassesDirectory}"/>
    <path refid="testPath"/>
  </classpath>
  <javac source="1.7" target="1.7" debug="on" />
</groovyc>

It is rare to specify srcdir and destdir, the nested javac task is provided with the srcdir and destdir values from the enclosing groovyc task, and it is invariable the right thing to do just to leave this as is. To restate: the javac task gets the srcdir, destdir and classpath from the enclosing groovyc task.

More details about joint compilation can be found in the joint compilation section.

2.2.3. Gant

Gant is a tool for scripting Ant tasks using Groovy instead of XML to specify the logic. As such, it has exactly the same features as the Groovyc Ant task.

2.2.4. Gradle

Gradle is a build tool that allows you to leverage the flexibility of Ant, while keeping the simplicity of convention over configuration that tools like Maven offer. Builds are specified using a Groovy DSL, which offers great flexibility and succinctness.

2.2.5. Maven integration

There are several approaches to compiling Groovy code in your Maven projects. GMavenPlus is the most flexible and feature rich, but like most Groovy compiler tools, it can have difficulties with joint Java-Groovy projects (for the same reason GMaven and Gradle can have issues). The Groovy-Eclipse compiler plugin for Maven sidesteps the joint compilation issues. Read this for a deeper discussion of the benefits and disadvantages of the two approaches.

A third approach is to use Maven’s Ant plugin to compile a groovy project. Note that the Ant plugin is bound to the compile and test-compile phases of the build in the example below. It will be invoked during these phases and the contained tasks will be carried out which runs the Groovy compiler over the source and test directories. The resulting Java classes will coexist with and be treated like any standard Java classes compiled from Java source and will appear no different to the JRE, or the JUnit runtime.

<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>com.mycomp.MyGroovy</groupId>
    <artifactId>MyGroovy</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Maven Example building a Groovy project</name>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.1.6</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <configuration>
                            <tasks>
                                <mkdir dir="${basedir}/src/main/groovy"/>
                                <taskdef name="groovyc"
                                    classname="org.codehaus.groovy.ant.Groovyc">
                                    <classpath refid="maven.compile.classpath"/>
                                </taskdef>
                                <mkdir dir="${project.build.outputDirectory}"/>
                                <groovyc destdir="${project.build.outputDirectory}"
                                    srcdir="${basedir}/src/main/groovy/" listfiles="true">
                                    <classpath refid="maven.compile.classpath"/>
                                </groovyc>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <configuration>
                            <tasks>
                                <mkdir dir="${basedir}/src/test/groovy"/>
                                <taskdef name="groovyc"
                                    classname="org.codehaus.groovy.ant.Groovyc">
                                    <classpath refid="maven.test.classpath"/>
                                </taskdef>
                                <mkdir dir="${project.build.testOutputDirectory}"/>
                                <groovyc destdir="${project.build.testOutputDirectory}"
                                    srcdir="${basedir}/src/test/groovy/" listfiles="true">
                                    <classpath refid="maven.test.classpath"/>
                                </groovyc>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

This assumes you have a Maven project setup with groovy subfolders as peers to the java src and test subfolders. You can use the java/jar archetype to set this up then rename the java folders to groovy or keep the java folders and just create groovy peer folders. There exists, also a groovy plugin which has not been tested or used in production. After defining the build section as in the above example, you can invoke the typical Maven build phases normally. For example, mvn test will execute the test phase, compiling Groovy source and Groovy test source and finally executing the unit tests. If you run mvn jar it will execute the jar phase bundling up all of your compiled production classes into a jar after all of the unit tests pass. For more detail on Maven build phases consult the Maven2 documentation.

GMaven and GMavenPlus
GMaven

GMaven is the original Maven plugin for Groovy, supporting both compiling and scripting Groovy.

Important:

You should be aware that GMaven is not supported anymore and can have difficulties with joint compilation. GMavenPlus can be a good replacement, but if you are having problems with joint compilation, you might consider the Groovy Eclipse maven plugin.

GMavenPlus

GMavenPlus is a rewrite of GMaven and is in active development. It supports most of the features of GMaven (a couple notable exceptions being mojo Javadoc tags and support for older Groovy versions). Its joint compilation uses stubs (which means it has the same potential issues as GMaven and Gradle). The main advantages over its predecessor are that it supports recent Groovy versions, InvokeDynamic, Groovy on Android, and GroovyDoc.

GMaven 2

Unlike the name might seem to suggest, GMaven 2 is not aimed at replacing GMaven. In fact, it removes the non-scripting features of the GMaven plugin. It has not yet had any release and appears to be inactive currently.

The Groovy Eclipse Maven plugin

Groovy-Eclipse provides a compiler plugin for Maven. Using the compiler plugin, it is possible to compile your maven projects using the Groovy-Eclipse compiler.

The most recent version of the Groovy-Eclipse-Compiler plugin for maven is 2.9.1-01. The most recent version of the groovy-eclipse-batch artifact is 2.3.7-01. They are both available from maven central.

How to use the compiler plugin—Setting up the POM

In the plugin section, change the compiler used by the maven-compiler-plugin. Like the javac ant task, the maven-compiler-plugin does not actually compile, but rather delegates the compilation to a different artifact (in our case, the groovy-eclipse-batch artifact):

<build>
    ...
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
        <version>3.1</version>
        <configuration>
          <compilerId>groovy-eclipse-compiler</compilerId>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-eclipse-compiler</artifactId>
            <version>2.9.1-01</version>
          </dependency>
          <!-- for 2.8.0-01 and later you must have an explicit dependency on groovy-eclipse-batch -->
          <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-eclipse-batch</artifactId>
            <version>2.3.7-01</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
    ...
</build>

This will allow Groovy files to be compiled. The groovy-eclipse-compiler recognizes all settings supported by the maven-compiler-plugin.

Remember that you still need to specify a groovy artifact as a build dependency in addition to the maven-compiler-plugin dependency. The groovy dependency version should match the compiler version. Something like this:

<dependencies>
  ...
  <dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.3.7</version>
  </dependency>
  ...
</dependencies>

Note that the groovy-eclipse-compiler and groovy-eclipse-batch artifacts are available in Maven-central, so there is no need to explicitly declare any extra repositories.

Setting up the source folders

There are several ways to set up your maven project to recognize Groovy source files

Do nothing

The simplest way to set up your source folders is to do nothing at all: add all of your Groovy files to src/main/java and src/test/java. This requires absolutely no extra configuration and is easy to implement. However, this is not a standard maven approach to setting up your project. If you require a more standard maven approach, then it is possible to put your Groovy files in src/main/groovy and src/test/groovy and you Java files in src/main/java and src/test/java. There are several ways of doing this.

Do almost nothing

If there is at least one file (Java or not) in src/main/java, then all files in src/main/groovy will be found. If, however, src/main/java is empty, then src/main/groovy will be ignored. You can get around this by placing an empty file in src/main/java just so that src/main/groovy will be recognized. The same is true for src/test/java and src/test/groovy.

Use the groovy-eclipse-compiler mojo for configuring source folders

(You only need this approach if your project has an empty src/main/java or src/test/java.)

If your project has no Java files and you don’t want to add an empty file in src/main/java, then you can configure source files by referencing the groovy-eclipse-compiler mojo. Just add this to the plugins section of your pom:

<build>
  ...
  <plugin>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-eclipse-compiler</artifactId>
    <version>2.9.1-01</version>
    <extensions>true</extensions>
  </plugin>
  ...
</build>

The <extensions>true</extensions> section is important because this redefines the default lifecycle of your project so that an extra phase is added. This phase has an extra goal attached to it that adds the two Groovy source folders.

Use the build-helper-maven-plugin

(You only need this approach if your project has an empty src/main/java or src/test/java.)

The build-helper-maven-plugin allows you to do things like adding extra source folders to your project without needing to redefine the default lifecycle. You need to add this configuration to your build plugin section:

<build>
  ...
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.5</version>
    <executions>
      <execution>
        <id>add-source</id>
        <phase>generate-sources</phase>
        <goals>
          <goal>add-source</goal>
        </goals>
        <configuration>
          <sources>
            <source>src/main/groovy</source>
          </sources>
        </configuration>
      </execution>
      <execution>
        <id>add-test-source</id>
        <phase>generate-test-sources</phase>
        <goals>
          <goal>add-test-source</goal>
        </goals>
        <configuration>
          <sources>
            <source>src/test/groovy</source>
          </sources>
        </configuration>
      </execution>
    </executions>
  </plugin>
  ...
</build>

The benefit of using this approach is that you do not need to make any changes to the default lifecycle. The downside is, of course, that you need 31 lines of configuration to do this!

Source code

The source code for the plugin itself is available from the github repository.

Why another Groovy compiler for Maven? What about GMaven?

GMaven 2.0 and later no longer supports compilation.  You can read more about this on the GMaven 2 project page. GMaven 1.x is now deprecated.

GMaven 1.x had limitations over the groovy-eclipse-compiler and for the following reasons GMaven 2.0 compilation is no longer supported:

  1. The compiler plugin does not require the creation of Java stubs so that your Groovy files can compile against Java files. This will prevent some arcane compile errors from appearing.

  2. The Groovy-Eclipse compiler is the same inside Eclipse and inside Maven, and so configuration across the two platforms can be simplified.

  3. The compiler plugin is a standard compiler plugin for Maven. It therefore follows all allows all the same standard configuration that the Javac compiler plugin uses. This makes it simpler to introduce Groovy into an existing Maven project. All you need to do is change the compiler plugin that the pom references.

There are still some reasons to use GMaven:

  1. GroovyDoc tool is not supported because the compiler plugin does not produce stubs.

  2. Groovy Mojos are not supported.

  3. Groovy scripts cannot be executed in your poms.

Whether or not the Groovy-Eclipse compiler plugin for Maven is appropriate for your project will depend on your requirements.

Project Lombok

Project Lombok is compatible with the groovy-eclipse-compiler.  There is some extra configuration that you need to do. The lombok jar needs to be added to both the build and compile dependencies sections:

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.14.8</version>
</dependency>

Also, the following configuration needs to be added to the maven-compiler-plugin configuration:

<configuration>
  <compilerId>groovy-eclipse-compiler</compilerId>
  <verbose>true</verbose>
  <compilerArguments>
    <javaAgentClass>lombok.core.Agent</javaAgentClass>
  </compilerArguments>
  <fork>true</fork>
</configuration>
Groovy-Eclipse configurator for m2Eclipse

If you are going to be working with your maven project inside of Eclipse, it is strongly recommended that you use m2eclipse. And to use your Groovy projects with m2eclipse, you will need to install the Groovy-Eclipse configurator for m2eclipse. This feature is available any of the Groovy-Eclipse update sites (e.g., nightly, milestone, or release). Just go to your Eclipse update manager and add the Groovy-Eclipse update sites (if you haven’t done so already). Select the Groovy-Eclipse M2E integration.

The Groovy-Eclipse configurator for m2eclipse is not compatible with AspectJ or Scala. So you cannot use a joint AspectJ/Scala/Groovy project in Eclipse. These languages must be separated into separate sub-projects.

Where to find more information and report issues

More information is available in the Groovy-Eclipse Wiki. Any bugs or feature enhancements should be reported as Groovy-Eclipse Github Issues.

Joint compilation

Joint compilation means that the Groovy compiler will parse the Groovy source files, create stubs for all of them, invoke the Java compiler to compile the stubs along with Java sources, and then continue compilation in the normal Groovy compiler way. This allows mixing of Java and Groovy files without constraint.

Joint compilation can be enabled using the -j flag with the command-line compiler, or using using a nested tag and all the attributes and further nested tags as required for the Ant task.

It is important to know that if you don’t enable joint compilation and try to compile Java source files with the Groovy compiler, the Java source files will be compiled as if they were Groovy sources. In some situations, this might work since most of the Java syntax is compatible with Groovy, but semantics would be different.

2.2.6. Android support

It is possible to write an Android application in Groovy. However this requires a special version of the compiler, meaning that you cannot use the regular groovyc tool to target Android bytecode. In particular, Groovy provides specific JAR files for Android, which have a classifier of grooid. In order to make things easier, a Gradle plugin adds support for the Groovy language in the Android Gradle toolchain.

The plugin can be applied like this:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // ...
        classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.5'
    }
}

apply plugin: 'groovyx.grooid.groovy-android'

Then you will need to add a dependency on the grooid version of the Groovy compiler:

dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.0:grooid'
}

Note that if a Groovy jar does not provide a grooid classifier alternative, then it means that the jar is directly compatible with Android. In that case, you can add the dependency directly like this:

dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.0:grooid'       // requires the grooid classifier
    compile ('org.codehaus.groovy:groovy-json:2.4.0') {     // no grooid version available
        transitive = false                                  // so do not depend on non-grooid version
    }
}

Note that the transitive=false parameter for groovy-json will let Gradle download the JSON support jar without adding a dependency onto the normal jar of Groovy.

Please make sure to go to the plugin homepage in order to find the latest documentation and version.

2.3. Groovysh, the Groovy shell

2.3.1. Groovy : Groovy Shell

The Groovy Shell, aka. groovysh is a command-line application which allows easy access to evaluate Groovy expressions, define classes and run simple experiments.

Features
  • No need for go command to execute buffer.

  • Rich cross-platform edit-line editing, history and completion thanks to JLine2.

  • ANSI colors (prompt, exception traces, etc).

  • Simple, yet robust, command system with online help, user alias support and more.

  • User profile support

Command-line Options and Arguments

The shell supports several options to control verbosity, ANSI coloring and other features.

./bin/groovysh --help
usage: groovysh [options] [...]
  -C, --color[=FLAG]         Enable or disable use of ANSI colors
  -D, --define=NAME=VALUE    Define a system property
  -T, --terminal=TYPE        Specify the terminal TYPE to use
  -V, --version              Display the version
  -classpath                 Specify where to find the class files - must
                             be first argument
  -cp, --classpath           Aliases for '-classpath'
  -d, --debug                Enable debug output
  -e, --evaluate=arg         Evaluate option fist when starting
                             interactive session
  -h, --help                 Display this help message
  -q, --quiet                Suppress superfluous output
  -v, --verbose              Enable verbose output
Evaluating Expressions
Simple Expressions
println "Hello"
Evaluation Result

When a complete expression is found, it is compiled and evaluated. The result of the evaluation is stored into the _ variable.

Multi-line Expressions

Multi-line/complex expressions (like closure or class definitions) may be defined over several lines. When the shell detects that it has a complete expression it will compile and evaluate it.

Define a Class
class Foo {
    def bar() {
        println "baz"
    }
}
Use the Class
foo = new Foo()
foo.bar()
Variables

Shell variables are all untyped (i.e. no def or other type information).

This will set a shell variable:

foo = "bar"

But, this will evaluate a local variable and will not be saved to the shell’s environment:

def foo = "bar"

This behavior can be changed by activating interpreter mode.

Functions

Functions can be defined in the shell, and will be saved for later use.

Defining a function is easy:

groovy:000> def hello(name) {
groovy:001> println("Hello $name")
groovy:002> }

And then using it is as one might expect:

hello("Jason")

Internally the shell creates a closure to encapsulate the function and then binds the closure to a variable. So variables and functions share the same namespace.

Commands

The shell has a number of different commands, which provide rich access to the shell’s environment.

Commands all have a name and a shortcut (which is something like \h). Commands may also have some predefined system aliases. Users may also create their own aliases.

Recognized Commands
help

Display the list of commands (and aliases) or the help text for specific command.

The Command List

groovy:000> :help

For information about Groovy, visit:
    http://groovy-lang.org

Available commands:
  :help      (:h ) Display this help message
  ?          (:? ) Alias to: :help
  :exit      (:x ) Exit the shell
  :quit      (:q ) Alias to: :exit
  import     (:i ) Import a class into the namespace
  :display   (:d ) Display the current buffer
  :clear     (:c ) Clear the buffer and reset the prompt counter.
  :show      (:S ) Show variables, classes or imports
  :inspect   (:n ) Inspect a variable or the last result with the GUI object browser
  :purge     (:p ) Purge variables, classes, imports or preferences
  :edit      (:e ) Edit the current buffer
  :load      (:l ) Load a file or URL into the buffer
  .          (:. ) Alias to: :load
  :save      (:s ) Save the current buffer to a file
  :record    (:r ) Record the current session to a file
  :history   (:H ) Display, manage and recall edit-line history
  :alias     (:a ) Create an alias
  :set       (:= ) Set (or list) preferences
  :register  (:rc) Registers a new command with the shell
  :doc       (:D ) Opens a browser window displaying the doc for the argument

For help on a specific command type:
    :help <command>

Help for a Command

While in the interactive shell, you can ask for help for any command to get more details about its syntax or function. Here is an example of what happens when you ask for help for the help command:

groovy:000> :help :help

usage: :help [<command>]

Display the list of commands or the help text for <command>.
exit

Exit the shell.

This is the only way to exit the shell. Well, you can still CTRL-C, but the shell will complain about an abnormal shutdown of the JVM.

import

Add a custom import which will be included for all shell evaluations.

This command can be given at any time to add new imports.

display

Display the contents of the current buffer.

This only displays the buffer of an incomplete expression. Once the expression is complete, the buffer is rest. The prompt will update to show the size of the current buffer as well.

Example

groovy:000> class Foo {
groovy:001> def bar
groovy:002> def baz() {
groovy:003> display
 001> class Foo {
 002> def bar
 003> def baz() {
clear

Clears the current buffer, resetting the prompt counter to 000. Can be used to recover from compilation errors.

show

Show variables, classes or preferences or imports.

show variables

groovy:000> :show variables
Variables:
  _ = true

show classes

show imports

show preferences

show all

inspect

Opens the GUI object browser to inspect a variable or the result of the last evaluation.

purge

Purges objects from the shell.

purge variables

purge classes

purge imports

purge preferences

purge all

edit

Edit the current buffer in an external editor.

Currently only works on UNIX systems which have the EDITOR environment variable set, or have configured the editor preference.

load

Load one or more files (or urls) into the buffer.

save

Saves the buffer’s contents to a file.

record

Record the current session to a file.

record start

record stop

record status

history

Display, manage and recall edit-line history.

history show

history recall

history flush

history clear

alias

Create an alias.

doc

Opens a browser with documentation for the provided class. For example:

groovy:000> :doc java.util.List
http://docs.oracle.com/javase/7/docs/api/java/util/List.html
http://docs.groovy-lang.org/2.4.2-SNAPSHOT/html/groovy-jdk/java/util/List.html

will open two windows (or tabs, depending on your browser):

  • one for the JDK documentation

  • one for the GDK documentation

set

Set or list preferences.

Preferences

Some of aspects of groovysh behaviors can be customized by setting preferences. Preferences are set using the set command or the \= shortcut.

Recognized Preferences
interpreterMode

Allows the use of typed variables (i.e. def or other type information):

groovy:000> def x = 3
===> 3
groovy:000> x
===> 3

It’s especially useful for copy&pasting code from tutorials etc. into the running session.

verbosity

Set the shell’s verbosity level. Expected to be one of:

  • DEBUG

  • VERBOSE

  • INFO

  • QUIET

Default is INFO.

If this preference is set to an invalid value, then the previous setting will be used, or if there is none, then the preference is removed and the default is used.

colors

Set the shell’s use of colors.

Default is true.

show-last-result

Show the last result after an execution.

Default is true.

sanitize-stack-trace

Sanitize (trim-down/filter) stack traces.

Default is true.

editor

Configures the editor used by the edit command.

Default is the value of the system environment variable EDITOR.

Mac OS XTo use TextEdit, the default text editor on Mac OS X, configure: set editor /Applications/TextEdit.app/Contents/MacOS/TextEdit

Setting a Preference
groovy:000> :set verbosity DEBUG
Listing Preferences

To list the current set preferences (and their values):

groovy:000> :show preferences

Limitation: At the moment, there is no way to list all of the known/available preferences to be set.

Clearing Preferences (i.e. Resetting to Defaults)
groovy:000> :purge preferences
User Profile Scripts and State
Profile Scripts
$HOME/.groovy/groovysh.profile

This script, if it exists, is loaded when the shell starts up.

$HOME/.groovy/groovysh.rc

This script, if it exists, is loaded when the shell enters interactive mode.

State
$HOME/.groovy/groovysh.history

Edit-line history is stored in this file.

Custom commands

The register command allows you to register custom commands in the shell. For example, writing the following will register the Stats command:

groovy:000> :register Stats

where the Stats class is a class extending the org.codehaus.groovy.tools.shell.CommandSupport class. For example:

import org.codehaus.groovy.tools.shell.CommandSupport
import org.codehaus.groovy.tools.shell.Groovysh

class Stats extends CommandSupport {
    protected Stats(final Groovysh shell) {
        super(shell, 'stats', 'T')
    }

    public Object execute(List args) {
        println "Free memory: ${Runtime.runtime.freeMemory()}"
    }

}

Then the command can be called using:

groovy:000> :stats
stats
Free memory: 139474880
groovy:000>

Note that the command class must be found on classpath: you cannot define a new command from within the shell.

Troubleshooting

Please report any problems you run into. Please be sure to mark the JIRA issue with the Groovysh component.

Platform Problems
Problems loading the JLine DLL

On Windows, JLine2 (which is used for the fancy shell input/history/completion fluff), uses a tiny DLL file to trick the evil Windows faux-shell (CMD.EXE or COMMAND.COM) into providing Java with unbuffered input. In some rare cases, this might fail to load or initialize.

One solution is to disable the frills and use the unsupported terminal instance. You can do that on the command-line using the --terminal flag and set it to one of:

  • none

  • false

  • off

  • jline.UnsupportedTerminal

groovysh --terminal=none
Problems with Cygwin on Windows

Some people have issues when running groovysh with cygwin. If you have troubles, the following may help:

stty -icanon min 1 -echo
groovysh --terminal=unix
stty icanon echo

2.3.2. GMavenPlus Maven Plugin

GMavenPlus is a Maven plugin with goals that support launching a Groovy Shell or Groovy Console bound to a Maven project.

2.3.3. Gradle Groovysh Plugin

Gradle Groovysh Plugin is a Gradle plugin that provides gradle tasks to start a Groovy Shell bound to a Gradle project.

2.4. groovyConsole, the Groovy swing console

2.4.1. Groovy : Groovy Console

The Groovy Swing Console allows a user to enter and run Groovy scripts. This page documents the features of this user interface.

2.4.2. Basics

image

  1. Groovy Console is launched via groovyConsole or groovyConsole.bat, both located in $GROOVY_HOME/bin

  2. The Console has an input area and an output area.

  3. You type a Groovy script in the input area.

  4. When you select Run from the Actions menu, the console compiles the script and runs it.

  5. Anything that would normally be printed on System.out is printed in the output area.

  6. If the script returns a non-null result, that result is printed.

2.4.3. Features

Running Scripts

There are several shortcuts that you can use to run scripts or code snippets:

  • Ctrl+Enter and Ctrl+R are both shortcut keys for Run Script.

  • If you highlight just part of the text in the input area, then Groovy runs just that text.

  • The result of a script is the the value of the last expression executed.

  • You can turn the System.out capture on and off by selecting Capture System.out from the Actions menu

Editing Files

You can open any text file, edit it, run it (as a Groovy Script) and then save it again when you are finished.

  • Select File > Open (shortcut key ctrl+O) to open a file

  • Select File > Save (shortcut key ctrl+S) to save a file

  • Select File > New File (shortcut key ctrl+Q) to start again with a blank input area

History and results
  • You can pop-up a gui inspector on the last (non-null) result by selecting Inspect Last from the Actions menu. The inspector is a convenient way to view lists and maps.

  • The console remembers the last ten script runs. You can scroll back and forth through the history by selecting Next and Previous from the Edit menu. Ctrl-N and ctrl-P are convenient shortcut keys.

  • The last (non-null) result is bound to a variable named _ (an underscore).

  • The last result (null and non-null) for every run in the history is bound into a list variable named (two underscores). The result of the last run is [-1], the result of the second to last run is __[-2] and so forth.

Interrupting a script

The Groovy console is a very handy tool to develop scripts. Often, you will find yourself running a script multiple times until it works the way you want it to. However, what if your code takes too long to finish or worse, creates an infinite loop? Interrupting script execution can be achieved by clicking the interrupt button on the small dialog box that pops up when a script is executing or through the interrupt icon in the tool bar.

Toolbar

However, this may not be sufficient to interrupt a script: clicking the button will interrupt the execution thread, but if your code doesn’t handle the interrupt flag, the script is likely to keep running without you being able to effectively stop it. To avoid that, you have to make sure that the Script > Allow interruption menu item is flagged. This will automatically apply an AST transformation to your script which will take care of checking the interrupt flag (@ThreadInterrupt). This way, you guarantee that the script can be interrupted even if you don’t explicitly handle interruption, at the cost of extra execution time.

And more
  • You can change the font size by selecting Smaller Font or Larger Font from the Actions menu

  • The console can be run as an Applet thanks to groovy.ui.ConsoleApplet

  • Code is auto indented when you hit return

  • You can drag’n’drop a Groovy script over the text area to open a file

  • You can modify the classpath with which the script in the console is being run by adding a new JAR or a directory to the classpath from the Script menu

  • Error hyperlinking from the output area when a compilation error is expected or when an exception is thrown

2.4.4. Embedding the Console

To embed a Swing console in your application, simply create the Console object, load some variables, and then launch it. The console can be embedded in either Java or Groovy code. The Java code for this is:

import groovy.ui.Console;

    ...
    Console console = new Console();
    console.setVariable("var1", getValueOfVar1());
    console.setVariable("var2", getValueOfVar2());
    console.run();
    ...

Once the console is launched, you can use the variable values in Groovy code.

2.4.5. Visualizing script output results

You can customize the way script output results are visualized. Let’s see how we can customize this. For example, viewing a map result would show something like this:

image

What you see here is the usual textual representation of a Map. But, what if we enabled custom visualization of certain results? The Swing console allows you to do just that. First of all, you have to ensure that the visualization option is ticked: View → Visualize Script Results — for the record, all settings of the Groovy Console are stored and remembered thanks to the Preference API. There are a few result visualizations built-in: if the script returns a java.awt.Image, a javax.swing.Icon, or a java.awt.Component with no parent, the object is displayed instead of its toString() representation. Otherwise, everything else is still just represented as text. Now, create the following Groovy script in ~/.groovy/OutputTransforms.groovy:

import javax.swing.*

transforms << { result ->
    if (result instanceof Map) {
        def table = new JTable(
            result.collect{ k, v ->
                [k, v?.inspect()] as Object[]
            } as Object[][],
            ['Key', 'Value'] as Object[])
        table.preferredViewportSize = table.preferredSize
        return new JScrollPane(table)
    }
}

The Groovy Swing console will execute that script on startup, injecting a transforms list in the binding of the script, so that you can add your own script results representations. In our case, we transform the Map into a nice-looking Swing JTable. And we’re now able to visualize maps in a friendly and attractive fashion, as the screenshot below shows:

image

2.4.6. AST browser

Groovy Console can visualize the AST (Abstract Syntax Tree) representing the currently edited script, as shown by the screenshot below. This is particularly handy when you want to develop AST transformations.

AST Browser

2.5. groovydoc, the Groovy & Java documentation generator

GroovyDoc is a tool responsible for generating documentation from your code. It acts like the Javadoc tool in the Java world but is capable of handling both groovy and java files. The distribution comes with two ways of generating documentation: from command line or from Apache Ant. Other build tools like Maven or Gradle also offer wrappers for Groovydoc.

2.5.1. The groovydoc command line tool

The groovydoc command line can be invoked to generate groovydocs:

groovydoc [options] [packagenames] [sourcefiles]

where options must be picked from the following table:

Short version Long version Description

-windowtitle <text>

Browser window title for the documentation

-author

Include @author paragraphs (currently not used)

-charset <charset>

Charset for cross-platform viewing of generated documentation

-classpath, -cp

--classpath

Specify where to find the class files - must be first argument

-d

--destdir <dir>

Destination directory for output files

--debug

Enable debug output

-doctitle <html>

Include title for the overview page

-exclude <pkglist>

Specify a list of packages to exclude (separated by colons for all operating systems)

-fileEncoding <charset>

Charset for generated documentation files

-footer <html>

Include footer text for each page

-header <html>

Include header text for each page

-help

--help

Display help message

-nomainforscripts

Don’t include the implicit 'public static void main' method for scripts

-noscripts

Don’t process Groovy Scripts

-overview <file>

Read overview documentation from HTML file

-package

Show package/protected/public classes and members

-private

Show all classes and members

-protected

Show protected/public classes and members (default)

-public

Show only public classes and members

-quiet

Suppress superfluous output

-sourcepath <pathlist>

Specify where to find source files (dirs separated by platform path separator)

-stylesheetfile <path>

File to change style of the generated documentation

-verbose

Enable verbose output

--version

Display the version

2.5.2. The groovydoc Ant task

The groovydoc Ant task allows generating groovydocs from an Ant build.

Required taskdef

Assuming groovy-all-2.4.4.jar is in my.classpath you will need to declare this task at some point in the build.xml prior to the groovydoc task being invoked.

<taskdef name         = "groovydoc"
         classname    = "org.codehaus.groovy.ant.Groovydoc"
         classpathref = "my.classpath"/>
<groovydoc> Attributes
Attribute Description Required

private

Show all classes and members (i.e. including private ones) if set to ``true''.

No

destdir

Location to store the class files.

Yes

sourcepath

The sourcepath to use.

No

packagenames

Comma separated list of package files (with terminating wildcard).

No

use

Create class and package usage pages.

No

windowtitle

Browser window title for the documentation (text).

No

doctitle

Include title for the package index(first) page (html-code).

No

header

Include header text for each page (html-code).

No

footer

Include footer text for each page (html-code).

No

overview

Read overview documentation from HTML file.

No

<groovydoc> Nested Elements

Create link to groovydoc/javadoc output at the given URL.

Attribute Description Required

href

Base URL of external site

Yes

packages

Comma separated list of package prefixes

Yes

Example #1 - <groovydoc> Ant task
<taskdef name           = "groovydoc"
         classname      = "org.codehaus.groovy.ant.Groovydoc"
         classpathref   = "path_to_groovy_all"/>

<groovydoc destdir      = "${docsDirectory}/gapi"
           sourcepath   = "${mainSourceDirectory}"
           packagenames = "**.*"
           use          = "true"
           windowtitle  = "${title}"
           doctitle     = "${title}"
           header       = "${title}"
           footer       = "${docFooter}"
           overview     = "src/main/overview.html"
           private      = "false">
        <link packages="java.,org.xml.,javax.,org.xml." href="http://docs.oracle.com/javase/8/docs/api/"/>
        <link packages="org.apache.tools.ant."          href="http://docs.groovy-lang.org/docs/ant/api/"/>
        <link packages="org.junit.,junit.framework."    href="http://junit.org/apidocs/"/>
        <link packages="groovy.,org.codehaus.groovy."   href="http://docs.groovy-lang.org/latest/html/api/"/>
        <link packages="org.codehaus.gmaven."           href="http://groovy.github.io/gmaven/apidocs/"/>
</groovydoc>
Example #2 - Executing <groovydoc> from Groovy
def ant = new AntBuilder()
ant.taskdef(name: "groovydoc", classname: "org.codehaus.groovy.ant.Groovydoc")
ant.groovydoc(
    destdir      : "${docsDirectory}/gapi",
    sourcepath   : "${mainSourceDirectory}",
    packagenames : "**.*",
    use          : "true",
    windowtitle  : "${title}",
    doctitle     : "${title}",
    header       : "${title}",
    footer       : "${docFooter}",
    overview     : "src/main/overview.html",
    private      : "false") {
        link(packages:"java.,org.xml.,javax.,org.xml.",href:"http://docs.oracle.com/javase/8/docs/api/")
        link(packages:"groovy.,org.codehaus.groovy.",  href:"http://docs.groovy-lang.org/latest/html/api/")
        link(packages:"org.apache.tools.ant.",         href:"http://docs.groovy-lang.org/docs/ant/api/")
        link(packages:"org.junit.,junit.framework.",   href:"http://junit.org/apidocs/")
        link(packages:"org.codehaus.gmaven.",          href:"http://groovy.github.io/gmaven/apidocs/")
}
Custom templates

The groovydoc Ant task supports custom templates, but it requires two steps:

  1. A custom groovydoc class

  2. A new groovydoc task definition

Custom Groovydoc class

The first step requires you to extend the Groovydoc class, like in the following example:

package org.codehaus.groovy.tools.groovydoc;

import org.codehaus.groovy.ant.Groovydoc;

/**
 * Overrides GroovyDoc's default class template - for testing purpose only.
 *
 * @author Andre Steingress
 */
public class CustomGroovyDoc extends Groovydoc {

    @Override
    protected String[] getClassTemplates() {
        return new String[]{"org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html"};
    }
}

You can override the following methods:

  • getClassTemplates for class-level templates

  • getPackageTemplates for package-level templates

  • getDocTemplates for top-level templates

You can find the list of default templates in the org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo class.

Using the custom groovydoc task

Once you’ve written the class, using it is just a matter of redefining the groovydoc task:

<taskdef name           = "groovydoc"
         classname      = "org.codehaus.groovy.ant.CustomGroovyDoc"
         classpathref   = "path_to_groovy_all"/>

Please note that template customization is provided as is. APIs are subject to change, so you must consider this as a fragile feature.

2.5.3. GMavenPlus Maven Plugin

GMavenPlus is a Maven plugin with goals that support GroovyDoc generation.

2.6. IDE integration

The Groovy language is supported by lots of IDEs and text editors.

Editor Support level Syntax highlighting Code completion Refactoring

UltraEdit

Yes

No

No

Groovy Eclipse Plugin

Yes

Yes

Yes

IntelliJ IDEA

Yes

Yes

Yes

Netbeans

Yes

Yes

Yes

Groovy and Grails Toolsuite

Yes

Yes

Yes

Groovy Emacs Modes

Yes

No

No

TextMate

Yes

No

No

vim

Yes

No

No

3. User Guides

3.1. Getting started

3.1.1. Download

In this download area, you will be able to download the distribution (binary and source), the Windows installer and the documentation for Groovy.

For a quick and effortless start on Mac OSX, Linux or Cygwin, you can use GVM (the Groovy enVironment Manager) to download and configure any Groovy version of your choice. Basic instructions can be found below.

Stable

You can learn more about this version in the release notes or in the changelog.

If you plan on using invokedynamic support, read those notes.

Snapshots

For those who want to test the very latest versions of Groovy and live on the bleeding edge, you can use our snapshot builds. As soon as a build succeeds on our continuous integration server a snapshot is deployed to Artifactory’s OSS snapshot repository.

Prerequisites

Groovy 2.4 requires Java 6+ with full support up to Java 8. There are currently some known issues for some aspects when using Java 9 snapshots. The groovy-nio module requires Java 7+. Using Groovy’s invokeDynamic features require Java 7+ but we recommend Java 8.

The Groovy CI server is also useful to look at to confirm supported Java versions for different Groovy releases. The test suite (getting close to 10000 tests) runs for the currently supported streams of Groovy across all the main versions of Java each stream supports.

3.1.2. Maven Repository

If you wish to embed Groovy in your application, you may just prefer to point to your favourite maven repositories or the JCenter maven repository.

Stable Release
Gradle Maven Explanation

'org.codehaus.groovy:groovy:2.4.4'

<groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <version>2.4.4</version>

Just the core of groovy without the modules (see below).

'org.codehaus.groovy:groovy-$module:2.4.4'

<groupId>org.codehaus.groovy</groupId> <artifactId>groovy-$module</artifactId> <version>2.4.4</version>

"$module" stands for the different optional groovy modules "ant", "bsf", "console", "docgenerator", "groovydoc", "groovysh", "jmx", "json", "jsr223", "servlet", "sql", "swing", "test", "testng" and "xml". Example: <artifactId>groovy-sql</artifactId>

'org.codehaus.groovy:groovy-all:2.4.4'

<groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.4</version>

The core plus all the modules. Optional dependencies are marked as optional. You may need to include some of the optional dependencies to use some features of Groovy, e.g. AntBuilder, GroovyMBeans, etc.

To use the InvokeDynamic version of the jars just append ':indy' for Gradle or <classifier>indy</classifier> for Maven.

3.1.3. GVM (the Groovy enVironment Manager)

This tool makes installing Groovy on any Bash platform (Mac OSX, Linux, Cygwin, Solaris or FreeBSD) very easy.

Simply open a new terminal and enter:

$ curl -s get.gvmtool.net | bash

Follow the instructions on-screen to complete installation.

Open a new terminal or type the command:

$ source "$HOME/.gvm/bin/gvm-init.sh"

Then install the latest stable Groovy:

$ gvm install groovy

After installation is complete and you’ve made it your default version, test it with:

$ groovy -version

That’s all there is to it!

3.1.4. Other ways to get Groovy

Installation on Mac OS X
MacPorts

If you’re on MacOS and have MacPorts installed, you can run:

sudo port install groovy
Homebrew

If you’re on MacOS and have Homebrew installed, you can run:

brew install groovy
Installation on Windows

If you’re on Windows, you can also use the NSIS Windows installer.

Other Distributions

You may download other distributions of Groovy from this site.

Source Code

If you prefer to live on the bleeding edge, you can also grab the source code from GitHub.

IDE plugin

If you are an IDE user, you can just grab the latest IDE plugin and follow the plugin installation instructions.

3.1.5. Install Binary

These instructions describe how to install a binary distribution of Groovy.

  • First, Download a binary distribution of Groovy and unpack it into some file on your local file system.

  • Set your GROOVY_HOME environment variable to the directory you unpacked the distribution.

  • Add GROOVY_HOME/bin to your PATH environment variable.

  • Set your JAVA_HOME environment variable to point to your JDK. On OS X this is /Library/Java/Home, on other unixes its often /usr/java etc. If you’ve already installed tools like Ant or Maven you’ve probably already done this step.

You should now have Groovy installed properly. You can test this by typing the following in a command shell:

groovysh

Which should create an interactive groovy shell where you can type Groovy statements. Or to run the Swing interactive console type:

groovyConsole

To run a specific Groovy script type:

groovy SomeScript

3.2. Differences with Java

Groovy tries to be as natural as possible for Java developers. We’ve tried to follow the principle of least surprise when designing Groovy, particularly for developers learning Groovy who’ve come from a Java background.

Here we list all the major differences between Java and Groovy.

3.2.1. Default imports

All these packages and classes are imported by default, i.e. you do not have to use an explicit import statement to use them:

  • java.io.*

  • java.lang.*

  • java.math.BigDecimal

  • java.math.BigInteger

  • java.net.*

  • java.util.*

  • groovy.lang.*

  • groovy.util.*

3.2.2. Multi-methods

In Groovy, the methods which will be invoked are chosen at runtime. This is called runtime dispatch or multi-methods. It means that the method will be chosen based on the types of the arguments at runtime. In Java, this is the opposite: methods are chosen at compile time, based on the declared types.

The following code, written as Java code, can be compiled in both Java and Groovy, but it will behave differently:

int method(String arg) {
    return 1;
}
int method(Object arg) {
    return 2;
}
Object o = "Object";
int result = method(o);

In Java, you would have:

assertEquals(2, result);

Whereas in Groovy:

assertEquals(1, result);

That is because Java will use the static information type, which is that o is declared as an Object, whereas Groovy will choose at runtime, when the method is actually called. Since it is called with a String, then the String version is called.

3.2.3. Array initializers

In Groovy, the { …​ } block is reserved for closures. That means that you cannot create array literals with this syntax:

int[] array = { 1, 2, 3}

You actually have to use:

int[] array = [1,2,3]

3.2.4. Package scope visibility

In Groovy, omitting a modifier on a field doesn’t result in a package-private field like in Java:

class Person {
    String name
}

Instead, it is used to create a property, that is to say a private field, an associated getter and an associated setter.

It is possible to create a package-private field by annotating it with @PackageScope:

class Person {
    @PackageScope String name
}

3.2.5. ARM blocks

ARM (Automatic Resource Management) block from Java 7 are not supported in Groovy. Instead, Groovy provides various methods relying on closures, which have the same effect while being more idiomatic. For example:

Path file = Paths.get("/path/to/file");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

} catch (IOException e) {
    e.printStackTrace();
}

can be written like this:

new File('/path/to/file').eachLine('UTF-8') {
   println it
}

or, if you want a version closer to Java:

new File('/path/to/file').withReader('UTF-8') { reader ->
   reader.eachLine {
       println it
   }
}

3.2.6. Inner classes

The implementation of anonymous inner classes and nested classes follows the Java lead, but you should not take out the Java Language Spec and keep shaking the head about things that are different. The implementation done looks much like what we do for groovy.lang.Closure, with some benefits and some differences. Accessing private fields and methods for example can become a problem, but on the other hand local variables don’t have to be final.
Static inner classes

Here’s an example of static inner class:

class A {
    static class B {}
}

new A.B()

The usage of static inner classes is the best supported one. If you absolutely need an inner class, you should make it a static one.

Anonymous Inner Classes
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

CountDownLatch called = new CountDownLatch(1)

Timer timer = new Timer()
timer.schedule(new TimerTask() {
    void run() {
        called.countDown()
    }
}, 0)

assert called.await(10, TimeUnit.SECONDS)
Creating Instances of Non-Static Inner Classes

In Java you can do this:

public class Y {
    public class X {}
    public X foo() {
        return new X();
    }
    public static X createX(Y y) {
        return y.new X();
    }
}

Groovy doesn’t support the y.new X() syntax. Instead, you have to write new X(y), like in the code below:

public class Y {
    public class X {}
    public X foo() {
        return new X()
    }
    public static X createX(Y y) {
        return new X(y)
    }
}
Caution though, Groovy supports calling methods with one parameter without giving an argument. The parameter will then have the value null. Basically the same rules apply to calling a constructor. There is a danger that you will write new X() instead of new X(this) for example. Since this might also be the regular way we have not yet found a good way to prevent this problem.

3.2.7. Lambdas

Java 8 supports lambdas and method references:

Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);

Java 8 lambdas can be more or less considered as anonymous inner classes. Groovy doesn’t support that syntax, but has closures instead:

Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)

3.2.8. GStrings

As double-quoted string literals are interpreted as GString values, Groovy may fail with compile error or produce subtly different code if a class with String literal containing a dollar character is compiled with Groovy and Java compiler.

While typically, Groovy will auto-cast between GString and String if an API declares the type of a parameter, beware of Java APIs that accept an Object parameter and then check the actual type.

3.2.9. String and Character literals

Singly-quoted literals in Groovy are used for String, and double-quoted result in String or GString, depending whether there is interpolation in the literal.

assert 'c'.getClass()==String
assert "c".getClass()==String
assert "c${1}".getClass() in GString

Groovy will automatically cast a single-character String to char when assigning to a variable of type char. When calling methods with arguments of type char we need to either cast explicitly or make sure the value has been cast in advance.

char a='a'
assert Character.digit(a, 16)==10 : 'But Groovy does boxing'
assert Character.digit((char) 'a', 16)==10

try {
  assert Character.digit('a', 16)==10
  assert false: 'Need explicit cast'
} catch(MissingMethodException e) {
}

Groovy supports two styles of casting and in the case of casting to char there are subtle differences when casting a multi-char strings. The Groovy style cast is more lenient and will take the first character, while the C-style cast will fail with exception.

// for single char strings, both are the same
assert ((char) "c").class==Character
assert ("c" as char).class==Character

// for multi char strings they are not
try {
  ((char) 'cx') == 'c'
  assert false: 'will fail - not castable'
} catch(GroovyCastException e) {
}
assert ('cx' as char) == 'c'
assert 'cx'.asType(char) == 'c'

3.2.10. Behaviour of ==

In Java == means equality of primitive types or identity for objects. In Groovy == translates to a.compareTo(b)==0, iff they are Comparable, and a.equals(b) otherwise. To check for identity, there is is. E.g. a.is(b).

3.2.11. Different keywords

There are a few more keywords in Groovy than in Java. Don’t use them for variable names etc.

  • in

  • trait

3.3. Groovy Development Kit

3.3.1. Working with IO

Groovy provides a number of helper methods for working with I/O. While you could use standard Java code in Groovy to deal with those, Groovy provides much more convenient ways to handle files, streams, readers, …​

In particular, you should take a look at methods added to:

The following section focuses on sample idiomatic constructs using helper methods available above but is not meant to be a complete description of all available methods. For that, please read the GDK API.

Reading files

As a first example, let’s see how you would print all lines of a text file in Groovy:

new File(baseDir, 'haiku.txt').eachLine { line ->
    println line
}

The eachLine method is a method added to the File class automatically by Groovy and has many variants, for example if you need to know the line number, you can use this variant:

new File(baseDir, 'haiku.txt').eachLine { line, nb ->
    println "Line $nb: $line"
}

If for whatever reason the an exception is thrown in the eachLine body, the method makes sure that the resource is properly closed. This is true for all I/O resource methods that Groovy adds.

For example in some cases you will prefer to use a Reader, but still benefit from the automatic resource management from Groovy. In the next example, the reader will be closed even if the exception occurs:

def count = 0, MAXSIZE = 3
new File(baseDir,"haiku.txt").withReader { reader ->
    while (reader.readLine()) {
        if (++count > MAXSIZE) {
            throw new RuntimeException('Haiku should only have 3 verses')
        }
    }
}

Should you need to collect the lines of a text file into a list, you can do:

def list = new File(baseDir, 'haiku.txt').collect {it}

Or you can even leverage the as operator to get the contents of the file into an array of lines:

def array = new File(baseDir, 'haiku.txt') as String[]

How many times did you have to get the contents of a file into a byte[] and how much code does it require? Groovy makes it very easy actually:

byte[] contents = file.bytes

Working with I/O is not limited to dealing with files. In fact, a lot of operations rely on input/output streams, hence why Groovy adds a lot of support methods to those, as you can see in the documentation.

As an example, you can obtain an InputStream from a File very easily:

def is = new File(baseDir,'haiku.txt').newInputStream()
// do something ...
is.close()

However you can see that it requires you to deal with closing the inputstream. In Groovy it is in general a better idea to use the withInputStream idiom that will take care of that for you:

new File(baseDir,'haiku.txt').withInputStream { stream ->
    // do something ...
}
Writing files

Of course in some cases you won’t want to read but write a file. One of the options is to use a Writer:

new File(baseDir,'haiku.txt').withWriter('utf-8') { writer ->
    writer.writeLine 'Into the ancient pond'
    writer.writeLine 'A frog jumps'
    writer.writeLine 'Water’s sound!'
}

But for such a simple example, using the << operator would have been enough:

new File(baseDir,'haiku.txt') << '''Into the ancient pond
A frog jumps
Water’s sound!'''

Of course we do not always deal with text contents, so you could use the Writer or directly write bytes as in this example:

file.bytes = [66,22,11]

Of course you can also directly deal with output streams. For example, here is how you would create an output stream to write into a file:

def os = new File(baseDir,'data.bin').newOutputStream()
// do something ...
os.close()

However you can see that it requires you to deal with closing the output stream. Again it is in general a better idea to use the withOutputStream idiom that will handle the exceptions and close the stream in any case:

new File(baseDir,'data.bin').withOutputStream { stream ->
    // do something ...
}
Traversing file trees

In scripting contexts it is a common task to traverse a file tree in order to find some specific files and do something with them. Groovy provides multiple methods to do this. For example you can perform something on all files of a directory:

dir.eachFile { file ->                      (1)
    println file.name
}
dir.eachFileMatch(~/.*\.txt/) { file ->     (2)
    println file.name
}
1 executes the closure code on each file found in the directory
2 executes the closure code on files in the directory matching the specified pattern

Often you will have to deal with a deeper hierarchy of files, in which case you can use eachFileRecurse:

dir.eachFileRecurse { file ->                      (1)
    println file.name
}

dir.eachFileRecurse(FileType.FILES) { file ->      (2)
    println file.name
}
1 executes the closure code on each file or directory found in the directory, recursively
2 executes the closure code only on files, but recursively

For more complex traversal techniques you can use the traverse method, which requires you to set a special flag indicating what to do with the traversal:

dir.traverse { file ->
    if (file.directory && file.name=='bin') {
        FileVisitResult.TERMINATE                   (1)
    } else {
        println file.name
        FileVisitResult.CONTINUE                    (2)
    }

}
1 if the current file is a directory and its name is bin, stop the traversal
2 otherwise print the file name and continue
Data and objects

In Java it is not uncommon to serialize and deserialize data using the java.io.DataOutputStream and java.io.DataInputStream classes respectively. Groovy will make it even easier to deal with them. For example, you could serialize data into a file and deserialize it using this code:

boolean b = true
String message = 'Hello from Groovy'
// Serialize data into a file
file.withDataOutputStream { out ->
    out.writeBoolean(b)
    out.writeUTF(message)
}
// ...
// Then read it back
file.withDataInputStream { input ->
    assert input.readBoolean() == b
    assert input.readUTF() == message
}

And similarily, if the data you want to serialize implements the Serializable interface, you can proceed with an object output stream, as illustrated here:

Person p = new Person(name:'Bob', age:76)
// Serialize data into a file
file.withObjectOutputStream { out ->
    out.writeObject(p)
}
// ...
// Then read it back
file.withObjectInputStream { input ->
    def p2 = input.readObject()
    assert p2.name == p.name
    assert p2.age == p.age
}
Executing External Processes

The previous section described how easy it was to deal with files, readers or streams in Groovy. However in domains like system administration or devops it is often required to communicate with external processes.

Groovy provides a simple way to execute command line processes. Simply write the command line as a string and call the execute() method. E.g., on a *nix machine (or a windows machine with appropriate *nix commands installed), you can execute this:

def process = "ls -l".execute()             (1)
println "Found text ${process.text}"        (2)
1 executes the ls command in an external process
2 consume the output of the command and retrieve the text

The execute() method returns a java.lang.Process instance which will subsequently allow the in/out/err streams to be processed and the exit value from the process to be inspected etc.

e.g. here is the same command as above but we will now process the resulting stream a line at a time:

def process = "ls -l".execute()             (1)
process.in.eachLine { line ->               (2)
    println line                            (3)
}
1 executes the ls command in an external process
2 for each line of the input stream of the process
3 print the line

It is worth noting that in corresponds to an input stream to the standard output of the command. out will refer to a stream where you can send data to the process (its standard input).

Remember that many commands are shell built-ins and need special handling. So if you want a listing of files in a directory on a Windows machine and write:

def process = "dir".execute()
println "${process.text}"

you will receive an IOException saying  Cannot run program "dir": CreateProcess error=2, The system cannot find the file specified.

This is because dir is built-in to the Windows shell (cmd.exe) and can’t be run as a simple executable. Instead, you will need to write:

def process = "cmd /c dir".execute()
println "${process.text}"

Also, because this functionality currently makes use of java.lang.Process undercover, the deficiencies of that class must be taken into consideration. In particular, the javadoc for this class says:

Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock

Because of this, Groovy provides some additional helper methods which make stream handling for processes easier.

Here is how to gobble all of the output (including the error stream output) from your process:

def p = "rm -f foo.tmp".execute([], tmpDir)
p.consumeProcessOutput()
p.waitFor()

There are also variations of consumeProcessOutput that make use of StringBuffer, InputStream, OutputStream etc…​ For a complete list, please read the GDK API for java.lang.Process

In addition, these is a pipeTo command (mapped to | to allow overloading) which lets the output stream of one process be fed into the input stream of another process.

Here are some examples of use:

Pipes in action
proc1 = 'ls'.execute()
proc2 = 'tr -d o'.execute()
proc3 = 'tr -d e'.execute()
proc4 = 'tr -d i'.execute()
proc1 | proc2 | proc3 | proc4
proc4.waitFor()
if (proc4.exitValue()) {
    println proc4.err.text
} else {
    println proc4.text
}
Consuming errors
def sout = new StringBuilder()
def serr = new StringBuilder()
proc2 = 'tr -d o'.execute()
proc3 = 'tr -d e'.execute()
proc4 = 'tr -d i'.execute()
proc4.consumeProcessOutput(sout, serr)
proc2 | proc3 | proc4
[proc2, proc3].each { it.consumeProcessErrorStream(serr) }
proc2.withWriter { writer ->
    writer << 'testfile.groovy'
}
proc4.waitForOrKill(1000)
println "Standard output: $sout"
println "Standard error: $serr"

3.3.2. Working with collections

Groovy provides native support for various collection types, including lists, maps or ranges. Most of those are based on the Java collection types and decorated with additional methods found in the Groovy development kit.

Lists
List literals

You can create lists as follows. Notice that [] is the empty list expression.

def list = [5, 6, 7, 8]
assert list.get(2) == 7
assert list[2] == 7
assert list instanceof java.util.List

def emptyList = []
assert emptyList.size() == 0
emptyList.add(5)
assert emptyList.size() == 1

Each list expression creates an implementation of java.util.List.

Of course lists can be used as a source to construct another list:

def list1 = ['a', 'b', 'c']
//construct a new list, seeded with the same items as in list1
def list2 = new ArrayList<String>(list1)

assert list2 == list1 // == checks that each corresponding element is the same

// clone() can also be called
def list3 = list1.clone()
assert list3 == list1

A list is an ordered collection of objects:

def list = [5, 6, 7, 8]
assert list.size() == 4
assert list.getClass() == ArrayList     // the specific kind of list being used

assert list[2] == 7                     // indexing starts at 0
assert list.getAt(2) == 7               // equivalent method to subscript operator []
assert list.get(2) == 7                 // alternative method

list[2] = 9
assert list == [5, 6, 9, 8,]           // trailing comma OK

list.putAt(2, 10)                       // equivalent method to [] when value being changed
assert list == [5, 6, 10, 8]
assert list.set(2, 11) == 10            // alternative method that returns old value
assert list == [5, 6, 11, 8]

assert ['a', 1, 'a', 'a', 2.5, 2.5f, 2.5d, 'hello', 7g, null, 9 as byte]
//objects can be of different types; duplicates allowed

assert [1, 2, 3, 4, 5][-1] == 5             // use negative indices to count from the end
assert [1, 2, 3, 4, 5][-2] == 4
assert [1, 2, 3, 4, 5].getAt(-2) == 4       // getAt() available with negative index...
try {
    [1, 2, 3, 4, 5].get(-2)                 // but negative index not allowed with get()
    assert false
} catch (e) {
    assert e instanceof ArrayIndexOutOfBoundsException
}
List as a boolean expression

Lists can be evaluated as a boolean value:

assert ![]             // an empty list evaluates as false

//all other lists, irrespective of contents, evaluate as true
assert [1] && ['a'] && [0] && [0.0] && [false] && [null]
Iterating on a list

Iterating on elements of a list is usually done calling the each and eachWithIndex methods, which execute code on each item of a list:

[1, 2, 3].each {
    println "Item: $it" // `it` is an implicit parameter corresponding to the current element
}
['a', 'b', 'c'].eachWithIndex { it, i -> // `it` is the current element, while `i` is the index
    println "$i: $it"
}

In addition to iterating, it is often useful to create a new list by transforming each of its elements into something else. This operation, often called mapping, is done in Groovy thanks to the collect method:

assert [1, 2, 3].collect { it * 2 } == [2, 4, 6]

// shortcut syntax instead of collect
assert [1, 2, 3]*.multiply(2) == [1, 2, 3].collect { it.multiply(2) }

def list = [0]
// it is possible to give `collect` the list which collects the elements
assert [1, 2, 3].collect(list) { it * 2 } == [0, 2, 4, 6]
assert list == [0, 2, 4, 6]
Manipulating lists
Filtering and searching

The Groovy development kit contains a lot of methods on collections that enhance the standard collections with pragmatic methods, some of which are illustrated here:

assert [1, 2, 3].find { it > 1 } == 2           // find 1st element matching criteria
assert [1, 2, 3].findAll { it > 1 } == [2, 3]   // find all elements matching critieria
assert ['a', 'b', 'c', 'd', 'e'].findIndexOf {      // find index of 1st element matching criteria
    it in ['c', 'e', 'g']
} == 2

assert ['a', 'b', 'c', 'd', 'c'].indexOf('c') == 2  // index returned
assert ['a', 'b', 'c', 'd', 'c'].indexOf('z') == -1 // index -1 means value not in list
assert ['a', 'b', 'c', 'd', 'c'].lastIndexOf('c') == 4

assert [1, 2, 3].every { it < 5 }               // returns true if all elements match the predicate
assert ![1, 2, 3].every { it < 3 }
assert [1, 2, 3].any { it > 2 }                 // returns true if any element matches the predicate
assert ![1, 2, 3].any { it > 3 }

assert [1, 2, 3, 4, 5, 6].sum() == 21                // sum anything with a plus() method
assert ['a', 'b', 'c', 'd', 'e'].sum {
    it == 'a' ? 1 : it == 'b' ? 2 : it == 'c' ? 3 : it == 'd' ? 4 : it == 'e' ? 5 : 0
    // custom value to use in sum
} == 15
assert ['a', 'b', 'c', 'd', 'e'].sum { ((char) it) - ((char) 'a') } == 10
assert ['a', 'b', 'c', 'd', 'e'].sum() == 'abcde'
assert [['a', 'b'], ['c', 'd']].sum() == ['a', 'b', 'c', 'd']

// an initial value can be provided
assert [].sum(1000) == 1000
assert [1, 2, 3].sum(1000) == 1006

assert [1, 2, 3].join('-') == '1-2-3'           // String joining
assert [1, 2, 3].inject('counting: ') {
    str, item -> str + item                     // reduce operation
} == 'counting: 123'
assert [1, 2, 3].inject(0) { count, item ->
    count + item
} == 6

And here is idiomatic Groovy code for finding the maximum and minimum in a collection:

def list = [9, 4, 2, 10, 5]
assert list.max() == 10
assert list.min() == 2

// we can also compare single characters, as anything comparable
assert ['x', 'y', 'a', 'z'].min() == 'a'

// we can use a closure to specify the sorting behaviour
def list2 = ['abc', 'z', 'xyzuvw', 'Hello', '321']
assert list2.max { it.size() } == 'xyzuvw'
assert list2.min { it.size() } == 'z'

In addition to closures, you can use a Comparator to define the comparison criteria:

Comparator mc = { a, b -> a == b ? 0 : (a < b ? -1 : 1) }

def list = [7, 4, 9, -6, -1, 11, 2, 3, -9, 5, -13]
assert list.max(mc) == 11
assert list.min(mc) == -13

Comparator mc2 = { a, b -> a == b ? 0 : (Math.abs(a) < Math.abs(b)) ? -1 : 1 }


assert list.max(mc2) == -13
assert list.min(mc2) == -1

assert list.max { a, b -> a.equals(b) ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } == -13
assert list.min { a, b -> a.equals(b) ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } == -1
Adding or removing elements

We can use [] to assign a new empty list and << to append items to it:

def list = []
assert list.empty

list << 5
assert list.size() == 1

list << 7 << 'i' << 11
assert list == [5, 7, 'i', 11]

list << ['m', 'o']
assert list == [5, 7, 'i', 11, ['m', 'o']]

//first item in chain of << is target list
assert ([1, 2] << 3 << [4, 5] << 6) == [1, 2, 3, [4, 5], 6]

//using leftShift is equivalent to using <<
assert ([1, 2, 3] << 4) == ([1, 2, 3].leftShift(4))

We can add to a list in many ways:

assert [1, 2] + 3 + [4, 5] + 6 == [1, 2, 3, 4, 5, 6]
// equivalent to calling the `plus` method
assert [1, 2].plus(3).plus([4, 5]).plus(6) == [1, 2, 3, 4, 5, 6]

def a = [1, 2, 3]
a += 4      // creates a new list and assigns it to `a`
a += [5, 6]
assert a == [1, 2, 3, 4, 5, 6]

assert [1, *[222, 333], 456] == [1, 222, 333, 456]
assert [*[1, 2, 3]] == [1, 2, 3]
assert [1, [2, 3, [4, 5], 6], 7, [8, 9]].flatten() == [1, 2, 3, 4, 5, 6, 7, 8, 9]

def list = [1, 2]
list.add(3)
list.addAll([5, 4])
assert list == [1, 2, 3, 5, 4]

list = [1, 2]
list.add(1, 3) // add 3 just before index 1
assert list == [1, 3, 2]

list.addAll(2, [5, 4]) //add [5,4] just before index 2
assert list == [1, 3, 5, 4, 2]

list = ['a', 'b', 'z', 'e', 'u', 'v', 'g']
list[8] = 'x' // the [] operator is growing the list as needed
// nulls inserted if required
assert list == ['a', 'b', 'z', 'e', 'u', 'v', 'g', null, 'x']

It is however important that the + operator on a list is not mutating. Compared to <<, it will create a new list, which is often not what you want and can lead to performance issues.

The Groovy development kit also contains methods allowing you to easily remove elements from a list by value:

assert ['a','b','c','b','b'] - 'c' == ['a','b','b','b']
assert ['a','b','c','b','b'] - 'b' == ['a','c']
assert ['a','b','c','b','b'] - ['b','c'] == ['a']

def list = [1,2,3,4,3,2,1]
list -= 3           // creates a new list by removing `3` from the original one
assert list == [1,2,4,2,1]
assert ( list -= [2,4] ) == [1,1]

It is also possible to remove an element by referring to its index, in which case the list is mutated:

def list = [1,2,3,4,5,6,2,2,1]
assert list.remove(2) == 3          // remove the third element, and return it
assert list == [1,2,4,5,6,2,2,1]

In case you only want to remove the first element having the same value in a list, instead of removing all elements, you call call the remove method:

def list= ['a','b','c','b','b']
assert list.remove('c')             // remove 'c', and return true because element removed
assert list.remove('b')             // remove first 'b', and return true because element removed

assert ! list.remove('z')           // return false because no elements removed
assert list == ['a','b','b']

And removing all the elements in a list can be done by calling the clear method:

def list= ['a',2,'c',4]
list.clear()
assert list == []
Set operations

The Groovy development kit also includes methods making it easy to reason on sets:

assert 'a' in ['a','b','c']             // returns true if an element belongs to the list
assert ['a','b','c'].contains('a')      // equivalent to the `contains` method in Java
assert [1,3,4].containsAll([1,4])       // `containsAll` will check that all elements are found

assert [1,2,3,3,3,3,4,5].count(3) == 4  // count the number of elements which have some value
assert [1,2,3,3,3,3,4,5].count {
    it%2==0                             // count the number of elements which match the predicate
} == 2

assert [1,2,4,6,8,10,12].intersect([1,3,6,9,12]) == [1,6,12]

assert [1,2,3].disjoint( [4,6,9] )
assert ![1,2,3].disjoint( [2,4,6] )
Sorting

Working with collections often implies sorting. Groovy offers a variety of options to sort lists, from using closures to comparators, as in the following examples:

assert [6, 3, 9, 2, 7, 1, 5].sort() == [1, 2, 3, 5, 6, 7, 9]

def list = ['abc', 'z', 'xyzuvw', 'Hello', '321']
assert list.sort {
    it.size()
} == ['z', 'abc', '321', 'Hello', 'xyzuvw']

def list2 = [7, 4, -6, -1, 11, 2, 3, -9, 5, -13]
assert list2.sort { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } ==
        [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13]

Comparator mc = { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 }

// JDK 8+ only
// list2.sort(mc)
// assert list2 == [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13]

def list3 = [6, -3, 9, 2, -7, 1, 5]

Collections.sort(list3)
assert list3 == [-7, -3, 1, 2, 5, 6, 9]

Collections.sort(list3, mc)
assert list3 == [1, 2, -3, 5, 6, -7, 9]
Duplicating elements

The Groovy development kit also takes advantage of operator overloading to provide methods allowing duplication of elements of a list:

assert [1, 2, 3] * 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]
assert [1, 2, 3].multiply(2) == [1, 2, 3, 1, 2, 3]
assert Collections.nCopies(3, 'b') == ['b', 'b', 'b']

// nCopies from the JDK has different semantics than multiply for lists
assert Collections.nCopies(2, [1, 2]) == [[1, 2], [1, 2]] //not [1,2,1,2]
Maps
Map literals

In Groovy, maps (also known as associative arrays) can be created using the map literal syntax: [:]:

def map = [name: 'Gromit', likes: 'cheese', id: 1234]
assert map.get('name') == 'Gromit'
assert map.get('id') == 1234
assert map['name'] == 'Gromit'
assert map['id'] == 1234
assert map instanceof java.util.Map

def emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.put("foo", 5)
assert emptyMap.size() == 1
assert emptyMap.get("foo") == 5

Map keys are strings by default: [a:1] is equivalent to ['a':1]. This can be confusing if you define a variable named a and that you want the value of a to be the key in your map. If this is the case, then you must escape the key by adding parenthesis, like in the following example:

def a = 'Bob'
def ages = [a: 43]
assert ages['Bob'] == null // `Bob` is not found
assert ages['a'] == 43     // because `a` is a literal!

ages = [(a): 43]            // now we escape `a` by using parenthesis
assert ages['Bob'] == 43   // and the value is found!

In addition to map literals, it is possible, to get a new copy of a map, to clone it:

def map = [
        simple : 123,
        complex: [a: 1, b: 2]
]
def map2 = map.clone()
assert map2.get('simple') == map.get('simple')
assert map2.get('complex') == map.get('complex')
map2.get('complex').put('c', 3)
assert map.get('complex').get('c') == 3

The resulting map is a shallow copy of the original one, as illustrated in the previous example.

Map property notation

Maps also act like beans so you can use the property notation to get/set items inside the Map as long as the keys are strings which are valid Groovy identifiers:

def map = [name: 'Gromit', likes: 'cheese', id: 1234]
assert map.name == 'Gromit'     // can be used instead of map.get('Gromit')
assert map.id == 1234

def emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.foo = 5
assert emptyMap.size() == 1
assert emptyMap.foo == 5

Note: by design map.foo will always look for the key foo in the map. This means foo.class will return null on a map that doesn’t contain the class key. Should you really want to know the class, then you must use getClass():

def map = [name: 'Gromit', likes: 'cheese', id: 1234]
assert map.class == null
assert map.get('class') == null
assert map.getClass() == LinkedHashMap // this is probably what you want

map = [1      : 'a',
       (true) : 'p',
       (false): 'q',
       (null) : 'x',
       'null' : 'z']
assert map.containsKey(1) // 1 is not an identifier so used as is
assert map.true == null
assert map.false == null
assert map.get(true) == 'p'
assert map.get(false) == 'q'
assert map.null == 'z'
assert map.get(null) == 'x'
Iterating on maps

As usual in the Groovy development kit, idiomatic iteration on maps makes use of the each and eachWithIndex methods. It’s worth noting that maps created using the map literal notation are ordered, that is to say that if you iterate on map entries, it is guaranteed that the entries will be returned in the same order they were added in the map.

def map = [
        Bob  : 42,
        Alice: 54,
        Max  : 33
]

// `entry` is a map entry
map.each { entry ->
    println "Name: $entry.key Age: $entry.value"
}

// `entry` is a map entry, `i` the index in the map
map.eachWithIndex { entry, i ->
    println "$i - Name: $entry.key Age: $entry.value"
}

// Alternatively you can use key and value directly
map.each { key, value ->
    println "Name: $key Age: $value"
}

// Key, value and i as the index in the map
map.eachWithIndex { key, value, i ->
    println "$i - Name: $key Age: $value"
}
Manipulating maps
Adding or removing elements

Adding an element to a map can be done either using the put method, the subscript operator or using putAll:

def defaults = [1: 'a', 2: 'b', 3: 'c', 4: 'd']
def overrides = [2: 'z', 5: 'x', 13: 'x']

def result = new LinkedHashMap(defaults)
result.put(15, 't')
result[17] = 'u'
result.putAll(overrides)
assert result == [1: 'a', 2: 'z', 3: 'c', 4: 'd', 5: 'x', 13: 'x', 15: 't', 17: 'u']

Removing all the elements of a map can be done by calling the clear method:

def m = [1:'a', 2:'b']
assert m.get(1) == 'a'
m.clear()
assert m == [:]

Maps generated using the map literal syntax are using the object equals and hashcode methods. This means that you should never use an object which hash code is subject to change over time, or you wouldn’t be able to get the associated value back.

It is also worth noting that you should never use a GString as the key of a map, because the hash code of a GString is not the same as the hash code of an equivalent String:

def key = 'some key'
def map = [:]
def gstringKey = "${key.toUpperCase()}"
map.put(gstringKey,'value')
assert map.get('SOME KEY') == null
Keys, values and entries

We can inspect the keys, values, and entries in a view:

def map = [1:'a', 2:'b', 3:'c']

def entries = map.entrySet()
entries.each { entry ->
  assert entry.key in [1,2,3]
  assert entry.value in ['a','b','c']
}

def keys = map.keySet()
assert keys == [1,2,3] as Set

Mutating values returned by the view (be it a map entry, a key or a value) is highly discouraged because success of the operation directly depends on the type of the map being manipulated. In particular, Groovy relies on collections from the JDK that in general make no guarantee that a collection can safely be manipulated through keySet, entrySet, or values.

Filtering and searching

The Groovy development kit contains filtering, searching and collecting methods similar to those found for lists:

def people = [
    1: [name:'Bob', age: 32, gender: 'M'],
    2: [name:'Johnny', age: 36, gender: 'M'],
    3: [name:'Claire', age: 21, gender: 'F'],
    4: [name:'Amy', age: 54, gender:'F']
]

def bob = people.find { it.value.name == 'Bob' } // find a single entry
def females = people.findAll { it.value.gender == 'F' }

// both return entries, but you can use collect to retrieve the ages for example
def ageOfBob = bob.value.age
def agesOfFemales = females.collect {
    it.value.age
}

assert ageOfBob == 32
assert agesOfFemales == [21,54]

// but you could also use a key/pair value as the parameters of the closures
def agesOfMales = people.findAll { id, person ->
    person.gender == 'M'
}.collect { id, person ->
    person.age
}
assert agesOfMales == [32, 36]

// `every` returns true if all entries match the predicate
assert people.every { id, person ->
    person.age > 18
}

// `any` returns true if any entry matches the predicate

assert people.any { id, person ->
    person.age == 54
}
Grouping

We can group a list into a map using some criteria:

assert ['a', 7, 'b', [2, 3]].groupBy {
    it.class
} == [(String)   : ['a', 'b'],
      (Integer)  : [7],
      (ArrayList): [[2, 3]]
]

assert [
        [name: 'Clark', city: 'London'], [name: 'Sharma', city: 'London'],
        [name: 'Maradona', city: 'LA'], [name: 'Zhang', city: 'HK'],
        [name: 'Ali', city: 'HK'], [name: 'Liu', city: 'HK'],
].groupBy { it.city } == [
        London: [[name: 'Clark', city: 'London'],
                 [name: 'Sharma', city: 'London']],
        LA    : [[name: 'Maradona', city: 'LA']],
        HK    : [[name: 'Zhang', city: 'HK'],
                 [name: 'Ali', city: 'HK'],
                 [name: 'Liu', city: 'HK']],
]
Ranges

Ranges allow you to create a list of sequential values. These can be used as List since Range extends java.util.List.

Ranges defined with the .. notation are inclusive (that is the list contains the from and to value).

Ranges defined with the ..< notation are half-open, they include the first value but not the last value.

// an inclusive range
def range = 5..8
assert range.size() == 4
assert range.get(2) == 7
assert range[2] == 7
assert range instanceof java.util.List
assert range.contains(5)
assert range.contains(8)

// lets use a half-open range
range = 5..<8
assert range.size() == 3
assert range.get(2) == 7
assert range[2] == 7
assert range instanceof java.util.List
assert range.contains(5)
assert !range.contains(8)

//get the end points of the range without using indexes
range = 1..10
assert range.from == 1
assert range.to == 10

Note that int ranges are implemented efficiently, creating a lightweight Java object containing a from and to value.

Ranges can be used for any Java object which implements java.lang.Comparable for comparison and also have methods next() and previous() to return the next / previous item in the range. For example, you can create a range of String elements:

// an inclusive range
def range = 'a'..'d'
assert range.size() == 4
assert range.get(2) == 'c'
assert range[2] == 'c'
assert range instanceof java.util.List
assert range.contains('a')
assert range.contains('d')
assert !range.contains('e')

You can iterate on a range using a classic for loop:

for (i in 1..10) {
    println "Hello ${i}"
}

but alternatively you can achieve the same effect in a more Groovy idiomatic style, by iterating a range with each method:

(1..10).each { i ->
    println "Hello ${i}"
}

Ranges can be also used in the switch statement:

switch (years) {
    case 1..10: interestRate = 0.076; break;
    case 11..25: interestRate = 0.052; break;
    default: interestRate = 0.037;
}
Syntax enhancements for collections
GPath support

Thanks to the support of property notation for both lists and maps, Groovy provides syntactic sugar making it really easy to deal with nested collections, as illustrated in the following examples:

def listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22]]
assert listOfMaps.a == [11, 21] //GPath notation
assert listOfMaps*.a == [11, 21] //spread dot notation

listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
assert listOfMaps*.a == [11, 21, null] // caters for null values
assert listOfMaps*.a == listOfMaps.collect { it?.a } //equivalent notation
// But this will only collect non-null values
assert listOfMaps.a == [11,21]
Spread operator

The spread operator can be used to "inline" a collection into another. It is syntactic sugar which often avoids calls to putAll and facilitates the realization of one-liners:

assert [ 'z': 900,
         *: ['a': 100, 'b': 200], 'a': 300] == ['a': 300, 'b': 200, 'z': 900]
//spread map notation in map definition
assert [*: [3: 3, *: [5: 5]], 7: 7] == [3: 3, 5: 5, 7: 7]

def f = { [1: 'u', 2: 'v', 3: 'w'] }
assert [*: f(), 10: 'zz'] == [1: 'u', 10: 'zz', 2: 'v', 3: 'w']
//spread map notation in function arguments
f = { map -> map.c }
assert f(*: ['a': 10, 'b': 20, 'c': 30], 'e': 50) == 30

f = { m, i, j, k -> [m, i, j, k] }
//using spread map notation with mixed unnamed and named arguments
assert f('e': 100, *[4, 5], *: ['a': 10, 'b': 20, 'c': 30], 6) ==
        [["e": 100, "b": 20, "c": 30, "a": 10], 4, 5, 6]
The star-dot `*.' operator

The "star-dot" operator is a shortcut operator allowing you to call a method or a property on all elements of a collection:

assert [1, 3, 5] == ['a', 'few', 'words']*.size()

class Person {
    String name
    int age
}
def persons = [new Person(name:'Hugo', age:17), new Person(name:'Sandra',age:19)]
assert [17, 19] == persons*.age
Slicing with the subscript operator

You can index into lists, arrays, maps using the subscript expression. It is interesting that strings are considered as special kinds of collections in that context:

def text = 'nice cheese gromit!'
def x = text[2]

assert x == 'c'
assert x.class == String

def sub = text[5..10]
assert sub == 'cheese'

def list = [10, 11, 12, 13]
def answer = list[2,3]
assert answer == [12,13]

Notice that you can use ranges to extract part of a collection:

list = 100..200
sub = list[1, 3, 20..25, 33]
assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]

The subscript operator can be used to update an existing collection (for collection type which are not immutable):

list = ['a','x','x','d']
list[1..2] = ['b','c']
assert list == ['a','b','c','d']

It is worth noting that negative indices are allowed, to extract more easily from the end of a collection:

You can use negative indices to count from the end of the List, array, String etc.

text = "nice cheese gromit!"
x = text[-1]
assert x == "!"

def name = text[-7..-2]
assert name == "gromit"

Eventually, if you use a backwards range (the starting index is greater than the end index), then the answer is reversed.

text = "nice cheese gromit!"
name = text[3..1]
assert name == "eci"
Enhanced Collection Methods

In addition to lists, maps or ranges, Groovy offers a lot of additional methods for filtering, collecting, grouping, counting, …​ which are directly available on either collections or more easily iterables.

In particular, we invite you to read the Groovy development kit API docs and specifically:

  • methods added to Iterable can be found here

  • methods added to Iterator can be found here

  • methods added to Collection can be found here

  • methods added to List can be found here

  • methods added to Map can be found here

3.3.3. Handy utilities

ConfigSlurper

ConfigSlurper is a utility class for reading configuration files defined in the form of Groovy scripts. Like it is the case with Java *.properties files, ConfigSlurper allows a dot notation. But in addition, it allows for Closure scoped configuration values and arbitrary object types.

def config = new ConfigSlurper().parse('''
    app.date = new Date()  (1)
    app.age  = 42
    app {                  (2)
        name = "Test${42}"
    }
''')

assert config.app.date instanceof Date
assert config.app.age == 42
assert config.app.name == 'Test42'
1 Usage of the dot notation
2 Usage of Closure scopes as an alternative to the dot notation

As can be seen in the above example, the parse method can be used to retrieve groovy.util.ConfigObject instances. The ConfigObject is a specialized java.util.Map implementation that either returns the configured value or a new ConfigObject instance but never null.

def config = new ConfigSlurper().parse('''
    app.date = new Date()
    app.age  = 42
    app.name = "Test${42}"
''')

assert config.test != null   (1)
1 config.test has not been specified yet it returns a ConfigObject when being called.

In the case of a dot being part of a configuration variable name, it can be escaped by using single or double quotes.

def config = new ConfigSlurper().parse('''
    app."person.age"  = 42
''')

assert config.app."person.age" == 42

In addition, ConfigSlurper comes with support for environments. The environments method can be used to hand over a Closure instance that itself may consist of a several sections. Let’s say we wanted to create a particular configuration value for the development environment. When creating the ConfigSlurper instance we can use the ConfigSlurper(String) constructor to specify the target environment.

def config = new ConfigSlurper('development').parse('''
  environments {
       development {
           app.port = 8080
       }

       test {
           app.port = 8082
       }

       production {
           app.port = 80
       }
  }
''')

assert config.app.port == 8080
The ConfigSlurper environments aren’t restricted to any particular environment names. It solely depends on the ConfigSlurper client code what value are supported and interpreted accordingly.

The environments method is built-in but the registerConditionalBlock method can be used to register other method names in addition to the environments name.

def slurper = new ConfigSlurper()
slurper.registerConditionalBlock('myProject', 'developers')   (1)

def config = slurper.parse('''
  sendMail = true

  myProject {
       developers {
           sendMail = false
       }
  }
''')

assert !config.sendMail
1 Once the new block is registered ConfigSlurper can parse it.

For Java integration purposes the toProperties method can be used to convert the ConfigObject to a java.util.Properties object that might be stored to a *.properties text file. Be aware though that the configuration values are converted to String instances during adding them to the newly created Properties instance.

def config = new ConfigSlurper().parse('''
    app.date = new Date()
    app.age  = 42
    app {
        name = "Test${42}"
    }
''')

def properties = config.toProperties()

assert properties."app.date" instanceof String
assert properties."app.age" == '42'
assert properties."app.name" == 'Test42'
Expando

The Expando class can be used to create a dynamically expandable object. Despite its name it does not use the ExpandoMetaClass underneath. Each Expando object represents a standalone, dynamically-crafted instance that can be extended with properties (or methods) at runtime.

def expando = new Expando()
expando.name = 'John'

assert expando.name == 'John'

A special case occurs when a dynamic property registers a Closure code block. Once being registered it can be invoked as it would be done with a method call.

def expando = new Expando()
expando.toString = { -> 'John' }
expando.say = { String s -> "John says: ${s}" }

assert expando as String == 'John'
assert expando.say('Hi') == 'John says: Hi'
Observable list, map and set

Groovy comes with observable lists, maps and sets. Each of these collections trigger java.beans.PropertyChangeEvent events when elements are added, removed or changed. Note that a PropertyChangeEvent is not only signalling that a certain event has occurred, moreover, it holds information on the property name and the old/new value a certain property has been changed to.

Depending on the type of change that has happened, observable collections might fire more specialized PropertyChangeEvent types. For example, adding an element to an observable list fires an ObservableList.ElementAddedEvent event.

def event                                       (1)
def listener = {
    if (it instanceof ObservableList.ElementEvent)  {  (2)
        event = it
    }
} as PropertyChangeListener


def observable = [1, 2, 3] as ObservableList    (3)
observable.addPropertyChangeListener(listener)  (4)

observable.add 42                               (5)

assert event instanceof ObservableList.ElementAddedEvent

def elementAddedEvent = event as ObservableList.ElementAddedEvent
assert elementAddedEvent.changeType == ObservableList.ChangeType.ADDED
assert elementAddedEvent.index == 3
assert elementAddedEvent.oldValue == null
assert elementAddedEvent.newValue == 42
1 Declares a PropertyChangeEventListener that is capturing the fired events
2 ObservableList.ElementEvent and its descendant types are relevant for this listener
3 Registers the listener
4 Creates an ObservableList from the given list
5 Triggers an ObservableList.ElementAddedEvent event
Be aware that adding an element in fact causes two events to be triggered. The first is of type ObservableList.ElementAddedEvent, the second is a plain PropertyChangeEvent that informs listeners about the change of property size.

The ObservableList.ElementClearedEvent event type is another interesting one. Whenever multiple elements are removed, for example when calling clear(), it holds the elements being removed from the list.

def event
def listener = {
    if (it instanceof ObservableList.ElementEvent)  {
        event = it
    }
} as PropertyChangeListener


def observable = [1, 2, 3] as ObservableList
observable.addPropertyChangeListener(listener)

observable.clear()

assert event instanceof ObservableList.ElementClearedEvent

def elementClearedEvent = event as ObservableList.ElementClearedEvent
assert elementClearedEvent.values == [1, 2, 3]
assert observable.size() == 0

To get an overview of all the supported event types the reader is encouraged to have a look at the JavaDoc documentation or the source code of the observable collection in use.

ObservableMap and ObservableSet come with the same concepts as we have seen for ObservableList in this section.

3.4. Metaprogramming

The Groovy language supports two flavors of metaprogramming: runtime metaprogramming and compile-time metaprogramming. The first one allows altering the class model and the behavior of a program at runtime, while the second only occurs at compile-time. Both have pros and cons, that we will detail in this section.

3.4.1. Runtime metaprogramming

With runtime metaprogramming we can postpone to runtime the decision to intercept, inject and even synthesize methods of classes and interfaces. For a deep understanding of Groovy MOP we need to understand Groovy objects and Groovy’s method handling. In Groovy we work with three kinds of objects: POJO, POGO and Groovy Interceptors. Groovy allows metaprogramming for all types of objects but in different manner.

  • POJO - A regular Java object, whose class can be written in Java or any other language for the JVM.

  • POGO - A Groovy object, whose class is written in Groovy. It extends java.lang.Object and implements the groovy.lang.GroovyObject interface by default.

  • Groovy Interceptor - A Groovy object that implements the groovy.lang.GroovyInterceptable interface and has method-interception capability, which we’ll discuss in the GroovyInterceptable section.

For every method call Groovy checks whether the object is a POJO or a POGO. For POJOs, Groovy fetches it’s MetaClass from the groovy.lang.MetaClassRegistry and delegates method invocation to it. For POGOs, Groovy takes more steps, as illustrated in the following figure:

GroovyInterceptions
Figure 1. Groovy interception mechanism
GroovyObject interface

groovy.lang.GroovyObject is the main interface in Groovy as the Object class is in Java. GroovyObject has a default implementation in the groovy.lang.GroovyObjectSupport class and it is responsible to transfer invocation to the groovy.lang.MetaClass object. The GroovyObject source looks like this:

package groovy.lang;

public interface GroovyObject {

    Object invokeMethod(String name, Object args);

    Object getProperty(String propertyName);

    void setProperty(String propertyName, Object newValue);

    MetaClass getMetaClass();

    void setMetaClass(MetaClass metaClass);
}
invokeMethod

According to the schema in Runtime Metaprogramming this method is called when the method you called is not present on a Groovy object. Here is a simple example using a overriden invokeMethod() method:

class SomeGroovyClass {

    def invokeMethod(String name, Object args) {
        return "called invokeMethod $name $args"
    }

    def test() {
        return 'method exists'
    }
}

def someGroovyClass = new SomeGroovyClass()

assert someGroovyClass.test() == 'method exists'
assert someGroovyClass.someMethod() == 'called invokeMethod someMethod []'
get/setProperty

Every read access to a property can be intercepted by overriding the getProperty() method of the current object. Here is a simple example:

class SomeGroovyClass {

    def property1 = 'ha'
    def field2 = 'ho'
    def field4 = 'hu'

    def getField1() {
        return 'getHa'
    }

    def getProperty(String name) {
        if (name != 'field3')
            return metaClass.getProperty(this, name) (1)
        else
            return 'field3'
    }
}

def someGroovyClass = new SomeGroovyClass()

assert someGroovyClass.field1 == 'getHa'
assert someGroovyClass.field2 == 'ho'
assert someGroovyClass.field3 == 'field3'
assert someGroovyClass.field4 == 'hu'
1 Forwards the request to the getter for all properties except field3.

You can intercept write access to properties by overriding the setProperty() method:

class POGO {

    String property

    void setProperty(String name, Object value) {
        this.@"$name" = 'overriden'
    }
}

def pogo = new POGO()
pogo.property = 'a'

assert pogo.property == 'overriden'
get/setMetaClass

You can a access a objects metaClass or set your own MetaClass implementation for changing the default interception mechanism. For example you can write your own implementation of the MetaClass interface and assign to it to objects and accordingly change the interception mechanism:

// getMetaclass
someObject.metaClass

// setMetaClass
someObject.metaClass = new OwnMetaClassImplementation()
You can find an additional example in the GroovyInterceptable topic.
get/setAttribute

This functionality is related to the MetaClass implementation. In the default implementation you can access fields without invoking their getters and setters. The examples below demonstrate this approach:

class SomeGroovyClass {

    def field1 = 'ha'
    def field2 = 'ho'

    def getField1() {
        return 'getHa'
    }
}

def someGroovyClass = new SomeGroovyClass()

assert someGroovyClass.metaClass.getAttribute(someGroovyClass, 'field1') == 'ha'
assert someGroovyClass.metaClass.getAttribute(someGroovyClass, 'field2') == 'ho'
class POGO {

    private String field
    String property1

    void setProperty1(String property1) {
        this.property1 = "setProperty1"
    }
}

def pogo = new POGO()
pogo.metaClass.setAttribute(pogo, 'field', 'ha')
pogo.metaClass.setAttribute(pogo, 'property1', 'ho')

assert pogo.field == 'ha'
assert pogo.property1 == 'ho'
methodMissing

Groovy supports the concept of methodMissing. This method differs from invokeMethod in that it is only invoked in case of a failed method dispatch, when no method can be found for the given name and/or the given arguments:

class Foo {

   def methodMissing(String name, def args) {
        return "this is me"
   }
}

assert new Foo().someUnknownMethod(42l) == 'this is me'

Typically when using methodMissing it is possible to cache the result for the next time the same method is called.

For example consider dynamic finders in GORM. These are implemented in terms of methodMissing. The code resembles something like this:

class GORM {

   def dynamicMethods = [...] // an array of dynamic methods that use regex

   def methodMissing(String name, args) {
       def method = dynamicMethods.find { it.match(name) }
       if(method) {
          GORM.metaClass."$name" = { Object[] varArgs ->
             method.invoke(delegate, name, varArgs)
          }
          return method.invoke(delegate,name, args)
       }
       else throw new MissingMethodException(name, delegate, args)
   }
}

Notice how, if we find a method to invoke, we then dynamically register a new method on the fly using ExpandoMetaClass. This is so that the next time the same method is called it is more efficient. This way of using methodMissing does not have the overhead of invokeMethod and is not expensive from the second call on.

propertyMissing

Groovy supports the concept of propertyMissing for intercepting otherwise failing property resolution attempts. In the case of a getter method, propertyMissing takes a single String argument containing the property name:

class Foo {
   def propertyMissing(String name) { name }
}

assert new Foo().boo == 'boo'

The propertyMissing(String) method is only called when no getter method for the given property can be found by the Groovy runtime.

For setter methods a second propertyMissing definition can be added that takes an additional value argument:

class Foo {
   def storage = [:]
   def propertyMissing(String name, value) { storage[name] = value }
   def propertyMissing(String name) { storage[name] }
}

def f = new Foo()
f.foo = "bar"

assert f.foo == "bar"

As with methodMissing it is best practice to dynamically register new properties at runtime to improve the overall lookup performance.

methodMissing and propertyMissing methods that deal with static methods and properties can be added via the ExpandoMetaClass.
GroovyInterceptable

The groovy.lang.GroovyInterceptable interface is marker interface that extends GroovyObject and is used to notify the Groovy runtime that all methods should be intercepted through the method dispatcher mechanism of the Groovy runtime.

package groovy.lang;

public interface GroovyInterceptable extends GroovyObject {
}

When a Groovy object implements the GroovyInterceptable interface, it’s invokeMethod() is called for any method calls. Below you can see a simple example of a object of this type:

class Interception implements GroovyInterceptable {

    def definedMethod() { }

    def invokeMethod(String name, Object args) {
        'invokedMethod'
    }
}

The next piece of code is a test which shows that both calls to existing and non-existing methods will return the same value.

class InterceptableTest extends GroovyTestCase {

    void testCheckInterception() {
        def interception = new Interception()

        assert interception.definedMethod() == 'invokedMethod'
        assert interception.someMethod() == 'invokedMethod'
    }
}
We cannot use default groovy methods like println because these methods are injected into all groovy objects so they will be intercepted too.

If we want to intercept all methods call but do not want to implement the GroovyInterceptable interface we can implement invokeMethod() on an object’s MetaClass. This approach works for both POGOs and POJOs, as shown by this example:

class InterceptionThroughMetaClassTest extends GroovyTestCase {

    void testPOJOMetaClassInterception() {
        String invoking = 'ha'
        invoking.metaClass.invokeMethod = { String name, Object args ->
            'invoked'
        }

        assert invoking.length() == 'invoked'
        assert invoking.someMethod() == 'invoked'
    }

    void testPOGOMetaClassInterception() {
        Entity entity = new Entity('Hello')
        entity.metaClass.invokeMethod = { String name, Object args ->
            'invoked'
        }

        assert entity.build(new Object()) == 'invoked'
        assert entity.someMethod() == 'invoked'
    }
}
Additional information about MetaClass can be found in the MetaClasses section.
Categories

There are situations where it is useful if a class not under control had additional methods. In order to enable this capability, Groovy implements a feature borrowed from Objective-C, called Categories.

Categories are implemented with so-called category classes. A category class is special in that it needs to meet certain pre-defined rules for defining extension methods.

There are a few categories that are included in the system for adding functionality to classes that make them more usable within the Groovy environment:

Category classes aren’t enabled by default. To use the methods defined in a category class it is necessary to apply the scoped use method that is provided by the GDK and available from inside every Groovy object instance:

use(TimeCategory)  {
    println 1.minute.from.now       (1)
    println 10.hours.ago

    def someDate = new Date()       (2)
    println someDate - 3.months
}
1 TimeCategory adds methods to Integer
2 TimeCategory adds methods to Date

The use method takes the category class as its first parameter and a closure code block as second parameter. Inside the Closure access to the category methods is available. As can be seen in the example above even JDK classes like java.lang.Integer or java.util.Date can be enriched with user-defined methods.

A category needs not to be directly exposed to the user code, the following will also do:

class JPACategory{
  // Let's enhance JPA EntityManager without getting into the JSR committee
  static void persistAll(EntityManager em , Object[] entities) { //add an interface to save all
    entities?.each { em.persist(it) }
  }
}

def transactionContext = {
  EntityManager em, Closure c ->
  def tx = em.transaction
  try {
    tx.begin()
    use(JPACategory) {
      c()
    }
    tx.commit()
  } catch (e) {
    tx.rollback()
  } finally {
    //cleanup your resource here
  }
}

// user code, they always forget to close resource in exception, some even forget to commit, let's not rely on them.
EntityManager em; //probably injected
transactionContext (em) {
 em.persistAll(obj1, obj2, obj3)
 // let's do some logics here to make the example sensible
 em.persistAll(obj2, obj4, obj6)
}

When we have a look at the groovy.time.TimeCategory class we see that the extension methods are all declared as static methods. In fact, this is one of the requirements that must be met by category classes for its methods to be successfully added to a class inside the use code block:

public class TimeCategory {

    public static Date plus(final Date date, final BaseDuration duration) {
        return duration.plus(date);
    }

    public static Date minus(final Date date, final BaseDuration duration) {
        final Calendar cal = Calendar.getInstance();

        cal.setTime(date);
        cal.add(Calendar.YEAR, -duration.getYears());
        cal.add(Calendar.MONTH, -duration.getMonths());
        cal.add(Calendar.DAY_OF_YEAR, -duration.getDays());
        cal.add(Calendar.HOUR_OF_DAY, -duration.getHours());
        cal.add(Calendar.MINUTE, -duration.getMinutes());
        cal.add(Calendar.SECOND, -duration.getSeconds());
        cal.add(Calendar.MILLISECOND, -duration.getMillis());

        return cal.getTime();
    }

    // ...

Another requirement is the first argument of the static method must define the type the method is attached to once being activated. The other arguments are the normal arguments the method will take as parameters.

Because of the parameter and static method convention, category method definitions may be a bit less intuitive than normal method definitions. As an alternative Groovy comes with a @Category annotation that transforms annotated classes into category classes at compile-time.

class Distance {
    def number
    String toString() { "${number}m" }
}

@Category(Number)
class NumberCategory {
    Distance getMeters() {
        new Distance(number: this)
    }
}

use (NumberCategory)  {
    assert 42.meters.toString() == '42m'
}

Applying the @Category annotation has the advantage of being able to use instance methods without the target type as a first parameter. The target type class is given as an argument to the annotation instead.

There is a distinct section on @Category in the compile-time metaprogramming section.
Metaclasses

(TBD)

Custom metaclasses

(TBD)

Delegating metaclass

(TBD)

Magic package

(TBD)

Per instance metaclass

(TBD)

ExpandoMetaClass

Groovy comes with a special MetaClass the so-called ExpandoMetaClass. It is special in that it allows for dynamically adding or changing methods, constructors, properties and even static methods by using a neat closure syntax.

Applying those modifications can be especially useful in mocking or stubbing scenarios as shown in the Testing Guide.

Every java.lang.Class is supplied by Groovy with a special metaClass property that will give you a reference to an ExpandoMetaClass instance. This instance can then be used to add methods or change the behaviour of already existing ones.

By default ExpandoMetaClass doesn’t do inheritance. To enable this you must call ExpandoMetaClass#enableGlobally() before your app starts such as in the main method or servlet bootstrap.

The following sections go into detail on how ExpandoMetaClass can be used in various scenarios.

Methods

Once the ExpandoMetaClass is accessed by calling the metaClass property, methods can added by using either the left shift << or the = operator.

Note that the left shift operator is used to append a new method. If the method already exists an exception will be thrown. If you want to replace a method you can use the = operator.

The operators are applied on a non-existent property of metaClass passing an instance of a Closure code block.

class Book {
   String title
}

Book.metaClass.titleInUpperCase << {-> title.toUpperCase() }

def b = new Book(title:"The Stand")

assert "THE STAND" == b.titleInUpperCase()

The example above shows how a new method can be added to a class by accessing the metaClass property and using the << or = operator to assign a Closure code block. The Closure parameters are interpreted as method parameters. Parameterless methods can be added by using the {→ …​} syntax.

Properties

ExpandoMetaClass supports two mechanisms for adding or overriding properties.

Firstly, it has support for declaring a mutable property by simply assigning a value to a property of metaClass:

class Book {
   String title
}

Book.metaClass.author = "Stephen King"
def b = new Book()

assert "Stephen King" == b.author

Another way is to add getter and/or setter methods by using the standard mechanisms for adding instance methods.

class Book {
  String title
}
Book.metaClass.getAuthor << {-> "Stephen King" }

def b = new Book()

assert "Stephen King" == b.author

In the source code example above the property is dictated by the closure and is a read-only property. It is feasible to add an equivalent setter method but then the property value needs to be stored for later usage. This could be done as shown in the following example.

class Book {
  String title
}

def properties = Collections.synchronizedMap([:])

Book.metaClass.setAuthor = { String value ->
   properties[System.identityHashCode(delegate) + "author"] = value
}
Book.metaClass.getAuthor = {->
   properties[System.identityHashCode(delegate) + "author"]
}

This is not the only technique however. For example in a servlet container one way might be to store the values in the currently executing request as request attributes (as is done in some cases in Grails).

Constructors

Constructors can be added by using a special constructor property. Either the << or = operator can be used to assign a Closure code block. The Closure arguments will become the constructor arguments when the code is executed at runtime.

class Book {
    String title
}
Book.metaClass.constructor << { String title -> new Book(title:title) }

def book = new Book('Groovy in Action - 2nd Edition')
assert book.title == 'Groovy in Action - 2nd Edition'
Be careful when adding constructors however, as it is very easy to get into stack overflow troubles.
Static Methods

Static methods can be added using the same technique as instance methods with the addition of the static qualifier before the method name.

class Book {
   String title
}

Book.metaClass.static.create << { String title -> new Book(title:title) }

def b = Book.create("The Stand")
Borrowing Methods

With ExpandoMetaClass it is possible to use Groovy’s method pointer syntax to borrow methods from other classes.

class Person {
    String name
}
class MortgageLender {
   def borrowMoney() {
      "buy house"
   }
}

def lender = new MortgageLender()

Person.metaClass.buyHouse = lender.&borrowMoney

def p = new Person()

assert "buy house" == p.buyHouse()
Dynamic Method Names

Since Groovy allows you to use Strings as property names this in turns allows you to dynamically create method and property names at runtime. To create a method with a dynamic name simply use the language feature of reference property names as strings.

class Person {
   String name = "Fred"
}

def methodName = "Bob"

Person.metaClass."changeNameTo${methodName}" = {-> delegate.name = "Bob" }

def p = new Person()

assert "Fred" == p.name

p.changeNameToBob()

assert "Bob" == p.name

The same concept can be applied to static methods and properties.

One application of dynamic method names can be found in the Grails web application framework. The concept of "dynamic codecs" is implemented by using dynamic method names.

HTMLCodec Class
class HTMLCodec {
    static encode = { theTarget ->
        HtmlUtils.htmlEscape(theTarget.toString())
    }

    static decode = { theTarget ->
    	HtmlUtils.htmlUnescape(theTarget.toString())
    }
}

The example above shows a codec implementation. Grails comes with various codec implementations each defined in a single class. At runtime there will be multiple codec classes in the application classpath. At application startup the framework adds a encodeXXX and a decodeXXX method to certain meta-classes where XXX is the first part of the codec class name (e.g. encodeHTML). This mechanism is in the following shown in some Groovy pseudo-code:

def codecs = classes.findAll { it.name.endsWith('Codec') }

codecs.each { codec ->
    Object.metaClass."encodeAs${codec.name-'Codec'}" = { codec.newInstance().encode(delegate) }
    Object.metaClass."decodeFrom${codec.name-'Codec'}" = { codec.newInstance().decode(delegate) }
}


def html = '<html><body>hello</body></html>'

assert '<html><body>hello</body></html>' == html.encodeAsHTML()
Runtime Discovery

At runtime it is often useful to know what other methods or properties exist at the time the method is executed. ExpandoMetaClass provides the following methods as of this writing:

  • getMetaMethod

  • hasMetaMethod

  • getMetaProperty

  • hasMetaProperty

Why can’t you just use reflection? Well because Groovy is different, it has the methods that are "real" methods and methods that are available only at runtime. These are sometimes (but not always) represented as MetaMethods. The MetaMethods tell you what methods are available at runtime, thus your code can adapt.

This is of particular use when overriding invokeMethod, getProperty and/or setProperty.

GroovyObject Methods

Another feature of ExpandoMetaClass is that it allows to override the methods invokeMethod, getProperty and setProperty, all of them can be found in the groovy.lang.GroovyObject class.

The following example shows how to override invokeMethod:

class Stuff {
   def invokeMe() { "foo" }
}

Stuff.metaClass.invokeMethod = { String name, args ->
   def metaMethod = Stuff.metaClass.getMetaMethod(name, args)
   def result
   if(metaMethod) result = metaMethod.invoke(delegate,args)
   else {
      result = "bar"
   }
   result
}

def stf = new Stuff()

assert "foo" == stf.invokeMe()
assert "bar" == stf.doStuff()

The first step in the Closure code is to lookup the MetaMethod for the given name and arguments. If the method can be found everything is fine and it is delegated to. If not, a dummy value is returned.

A MetaMethod is a method that is known to exist on the MetaClass whether added at runtime or at compile-time.

The same logic can be used to override setProperty or getProperty.

class Person {
   String name = "Fred"
}

Person.metaClass.getProperty = { String name ->
   def metaProperty = Person.metaClass.getMetaProperty(name)
   def result
   if(metaProperty) result = metaProperty.getProperty(delegate)
   else {
      result = "Flintstone"
   }
   result
}

def p = new Person()

assert "Fred" == p.name
assert "Flintstone" == p.other

The important thing to note here is that instead of a MetaMethod a MetaProperty instance is looked up. If that exists the getProperty method of the MetaProperty is called, passing the delegate.

Overriding Static invokeMethod

ExpandoMetaClass even allows for overriding static method with a special invokeMethod syntax.

class Stuff {
   static invokeMe() { "foo" }
}

Stuff.metaClass.'static'.invokeMethod = { String name, args ->
   def metaMethod = Stuff.metaClass.getStaticMetaMethod(name, args)
   def result
   if(metaMethod) result = metaMethod.invoke(delegate,args)
   else {
      result = "bar"
   }
   result
}

assert "foo" == Stuff.invokeMe()
assert "bar" == Stuff.doStuff()

The logic that is used for overriding the static method is the same as we’ve seen before for overriding instance methods. The only difference is the access to the metaClass.static property and the call to getStaticMethodName for retrieving the static MetaMethod instance.

Extending Interfaces

It is possible to add methods onto interfaces with ExpandoMetaClass. To do this however, it must be enabled globally using the ExpandoMetaClass.enableGlobally() method before application start-up.

List.metaClass.sizeDoubled = {-> delegate.size() * 2 }

def list = []

list << 1
list << 2

assert 4 == list.sizeDoubled()
Extension modules
Extending existing classes

An extension module allows you to add new methods to existing classes, including classes which are precompiled, like classes from the JDK. Those new methods, unlike those defined through a metaclass or using a category, are available globally. For example, when you write:

Standard extension method
def file = new File(...)
def contents = file.getText('utf-8')

The getText method doesn’t exist on the File class. However, Groovy knows it because it is defined in a special class, ResourceGroovyMethods:

ResourceGroovyMethods.java
public static String getText(File file, String charset) throws IOException {
 return IOGroovyMethods.getText(newReader(file, charset));
}

You may notice that the extension method is defined using a static method in a `helper'' class (where various extension methods are defined). The first argument of the `getText method corresponds to the receiver, while additional parameters correspond to the arguments of the extension method. So here, we are defining a method called getText on the File class (because the first argument is of type File), which takes a single argument as a parameter (the encoding String).

The process of creating an extension module is simple:

  • write an extension class like above

  • write a module descriptor file

Then you have to make the extension module visible to Groovy, which is as simple as having the extension module classes and descriptor available on classpath. This means that you have the choice:

  • either provide the classes and module descriptor directly on classpath

  • or bundle your extension module into a jar for reusability

An extension module may add two kind of methods to a class:

  • instance methods (to be called on an instance of a class)

  • static methods (to be called on the class itself)

Instance methods

To add an instance method to an existing class, you need to create an extension class. For example, let’s say you want to add a maxRetries method on Integer which accepts a closure and executes it at most n times until no exception is thrown. To do that, you only need to write the following:

MaxRetriesExtension.groovy
class MaxRetriesExtension {                                     (1)
    static void maxRetries(Integer self, Closure code) {        (2)
        int retries = 0
        Throwable e
        while (retries<self) {
            try {
                code.call()
                break
            } catch (Throwable err) {
                e = err
                retries++
            }
        }
        if (retries==0 && e) {
            throw e
        }
    }
}
1 The extension class
2 First argument of the static method corresponds to the receiver of the message, that is to say the extended instance

Then, after having declared your extension class, you can call it this way:

int i=0
5.maxRetries {
    i++
}
assert i == 1
i=0
try {
    5.maxRetries {
        throw new RuntimeException("oops")
    }
} catch (RuntimeException e) {
    assert i == 5
}
Static methods

It is also possible to add static methods to a class. In that case, the static method needs to be defined in its own file:

StaticStringExtension.groovy
class StaticStringExtension {                                       (1)
    static String greeting(String self) {                           (2)
        'Hello, world!'
    }
}
1 The static extension class
2 First argument of the static method corresponds to the class being extended and is unused

In which case you can call it directly on the String class:

assert String.greeting() == 'Hello, world!'
Module descriptor

For Groovy to be able to load your extension methods, you must declare your extension helper classes. You must create a file named org.codehaus.groovy.runtime.ExtensionModule into the META-INF/services directory:

org.codehaus.groovy.runtime.ExtensionModule
moduleName=Test module for specifications
moduleVersion=1.0-test
extensionClasses=support.MaxRetriesExtension
staticExtensionClasses=support.StaticStringExtension

The module descriptor requires 4 keys:

  • moduleName : the name of your module

  • moduleVersion: the version of your module. Note that version number is only used to check that you don’t load the same module in two different versions.

  • extensionClasses: the list of extension helper classes for instance methods. You can provide several classes, given that they are comma separated.

  • staticExtensionClasses: the list of extension helper classes for static methods. You can provide several classes, given that they are comma separated.

Note that it is not required for a module to define both static helpers and instance helpers, and that you may add several classes to a single module. You can also extend different classes in a single module without problem. It is even possible to use different classes in a single extension class, but it is recommended to group extension methods into classes by feature set.

Extension modules and classpath

It’s worth noting that you can’t use an extension which is compiled at the same time as code using it. That means that to use an extension, it has to be available on classpath, as compiled classes, before the code using it gets compiled. Usually, this means that you can’t have the test classes in the same source unit as the extension class itself. Since in general, test sources are separated from normal sources and executed in another step of the build, this is not an issue.

Compatibility with type checking

Unlike categories, extension modules are compatible with type checking: if they are found on classpath, then the type checker is aware of the extension methods and will not complain when you call them. It is also compatible with static compilation.

3.4.2. Compile-time metaprogramming

Compile-time metaprogramming in Groovy allows code generation at compile-time. Those transformations are altering the Abstract Syntax Tree (AST) of a program, which is why in Groovy we call it AST transformations. AST transformations allow you to hook into the compilation process, modify the AST and continue the compilation process to generate regular bytecode. Compared to runtime metaprogramming, this has the advantage of making the changes visible in the class file itself (that is to say, in the bytecode). Making it visible in the bytecode is important for example if you want the transformations to be part of the class contract (implementing interfaces, extending abstract classes, …​) or even if you need your class to be callable from Java (or other JVM languages). For example, an AST transformation can add methods to a class. If you do it with runtime metaprogramming, the new method would only be visible from Groovy. If you do the same using compile-time metaprogramming, the method would be visible from Java too. Last but not least, performance would likely be better with compile-time metaprogramming (because no initialization phase is required).

In this section, we will start with explaining the various compile-time transformations that are bundled with the Groovy distribution. In a subsequent section, we will describe how you can implement your own AST transformations and what are the disadvantages of this technique.

Available AST transformations

Groovy comes with various AST transformations covering different needs: reducing boilerplate (code generation), implementing design patterns (delegation, …​), logging, declarative concurrency, cloning, safer scripting, tweaking the compilation, implementing Swing patterns, testing and eventually managing dependencies. If none of those AST transformations cover your needs, you can still implement your own, as show in section Developing your own AST transformations.

AST transformations can be separated into two categories:

  • global AST transformations are applied transparently, globally, as soon as they are found on compile classpath

  • local AST transformations are applied by annotating the source code with markers. Unlike global AST transformations, local AST transformations may support parameters.

Groovy doesn’t ship with any global AST transformation, but you can find a list of local AST transformations available for you to use in your code here:

Code generation transformations

This category of transformation includes AST transformations which help removing boilerplate code. This is typically code that you have to write but that does not carry any useful information. By autogenerating this boilerplate code, the code you have to write is left clean and concise and the chance of introducing an error by getting such boilerplate code incorrect is reduced.

@groovy.transform.ToString

The @ToString AST transformation generates a human readable toString representation of the class. For example, annotating the Person class like below will automatically generate the toString method for you:

import groovy.transform.ToString

@ToString
class Person {
    String firstName
    String lastName
}

With this definition, then the following assertion passes, meaning that a toString method taking the field values from the class and printing them out has been generated:

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p.toString() == 'Person(Jack, Nicholson)'

The @ToString annotation accepts several parameters which are summarized in the following table:

Attribute Default value Description Example

includeNames

false

Whether to include names of properties in generated toString.

@ToString(includeNames=true)
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p.toString() == 'Person(firstName:Jack, lastName:Nicholson)'

excludes

Empty list

List of properties to exclude from toString

@ToString(excludes=['firstName'])
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p.toString() == 'Person(Nicholson)'

includes

Empty list

List of fields to include in toString

@ToString(includes=['lastName'])
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p.toString() == 'Person(Nicholson)'

includeSuper

False

Should superclass be included in toString

@ToString
class Id { long id }

@ToString(includeSuper=true)
class Person extends Id {
    String firstName
    String lastName
}

def p = new Person(id:1, firstName: 'Jack', lastName: 'Nicholson')
assert p.toString() == 'Person(Jack, Nicholson, Id(1))'

includeSuperProperties

False

Should super properties be included in toString

class Person {
    String name
}

@ToString(includeSuperProperties = true, includeNames = true)
class BandMember extends Person {
    String bandName
}

def bono = new BandMember(name:'Bono', bandName: 'U2').toString()

assert bono.toString() == 'BandMember(bandName:U2, name:Bono)'

includeFields

False

Should fields be included in toString, in addition to properties

@ToString(includeFields=true)
class Person {
    String firstName
    String lastName
    private int age
    void test() {
       age = 42
    }
}

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
p.test()
assert p.toString() == 'Person(Jack, Nicholson, 42)'

ignoreNulls

False

Should properties/fields with null value be displayed

@ToString(ignoreNulls=true)
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack')
assert p.toString() == 'Person(Jack)'

includePackage

False

Use fully qualified class name instead of simple name in toString

@ToString(includePackage=true)
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName:'Nicholson')
assert p.toString() == 'acme.Person(Jack, Nicholson)'

cache

False

Cache the toString string. Should only be set to true if the class is immutable.

@ToString(cache=true)
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName:'Nicholson')
def s1 = p.toString()
def s2 = p.toString()
assert s1 == s2
assert s1 == 'Person(Jack, Nicholson)'
assert s1.is(s2) // same instance
@groovy.transform.EqualsAndHashCode

The @EqualsAndHashCode AST transformation aims at generating equals and hashCode methods for you. The generated hashcode follows the best practices as described in Effective Java by Josh Bloch:

import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person(firstName: 'Jack', lastName: 'Nicholson')

assert p1==p2
assert p1.hashCode() == p2.hashCode()

There are several options available to tweak the behavior of @EqualsAndHashCode:

Attribute Default value Description Example

excludes

Empty list

List of properties to exclude from equals/hashCode

import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode(excludes=['firstName'])
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person(firstName: 'Bob', lastName: 'Nicholson')

assert p1==p2
assert p1.hashCode() == p2.hashCode()

includes

Empty list

List of fields to include in equals/hashCode

import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode(includes=['lastName'])
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person(firstName: 'Bob', lastName: 'Nicholson')

assert p1==p2
assert p1.hashCode() == p2.hashCode()

callSuper

False

Whether to include super in equals and hashCode calculations

import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode
class Living {
    String race
}

@EqualsAndHashCode(callSuper=true)
class Person extends Living {
    String firstName
    String lastName
}

def p1 = new Person(race:'Human', firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person(race: 'Human beeing', firstName: 'Jack', lastName: 'Nicholson')

assert p1!=p2
assert p1.hashCode() != p2.hashCode()

includeFields

False

Should fields be included in equals/hashCode, in addition to properties

@ToString(includeFields=true)
class Person {
    String firstName
    String lastName
    private int age
    void test() {
       age = 42
    }
}

def p = new Person(firstName: 'Jack', lastName: 'Nicholson')
p.test()
assert p.toString() == 'Person(Jack, Nicholson, 42)'

cache

False

Cache the hashCode computation. Should only be set to true if the class is immutable.

@ToString(cache=true)
class Person {
    String firstName
    String lastName
}

def p = new Person(firstName: 'Jack', lastName:'Nicholson')
def s1 = p.toString()
def s2 = p.toString()
assert s1 == s2
assert s1 == 'Person(Jack, Nicholson)'
assert s1.is(s2) // same instance

useCanEqual

True

Should equals call canEqual helper method.

@groovy.transform.TupleConstructor

The @TupleConstructor annotation aims at eliminating boilerplate code by generating constructors for you. A tuple constructor is created for each property, with default values (using the Java default values). For example, the following code will generate 3 constructors:

import groovy.transform.TupleConstructor

@TupleConstructor
class Person {
    String firstName
    String lastName
}

// traditional map-style constructor
def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
// generated tuple constructor
def p2 = new Person('Jack', 'Nicholson')
// generated tuple constructor with default value for second property
def p3 = new Person('Jack')

The first constructor is a no-arg constructor which allows the traditional map-style construction. It is worth noting that if the first property (or field) has type LinkedHashMap or if there is a single Map, AbstractMap or HashMap property (or field), then the map-style mapping is not available.

The other constructors are generated by taking the properties in the order they are defined. Groovy will generate as many constructors as they are properties (or fields, depending on the options).

The @TupleConstructor AST transformation accepts several configuration options:

Attribute Default value Description Example

excludes

Empty list

List of properties to exclude from tuple constructor generation

import groovy.transform.TupleConstructor

@TupleConstructor(excludes=['lastName'])
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person('Jack')
try {
    // will fail because the second property is excluded
    def p3 = new Person('Jack', 'Nicholson')
} catch (e) {
    assert e.message.contains ('Could not find matching constructor')
}

includes

Empty list

List of fields to include in tuple constructor generation

import groovy.transform.TupleConstructor

@TupleConstructor(includes=['firstName'])
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
def p2 = new Person('Jack')
try {
    // will fail because the second property is not included
    def p3 = new Person('Jack', 'Nicholson')
} catch (e) {
    assert e.message.contains ('Could not find matching constructor')
}

includeFields

False

Should fields be included in tuple constructor generation, in addition to properties

import groovy.transform.TupleConstructor

@TupleConstructor(includeFields=true)
class Person {
    String firstName
    String lastName
    private String occupation
    public String toString() {
        "$firstName $lastName: $occupation"
    }
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson', occupation: 'Actor')
def p2 = new Person('Jack', 'Nicholson', 'Actor')

assert p1.firstName == p2.firstName
assert p1.lastName == p2.lastName
assert p1.toString() == 'Jack Nicholson: Actor'
assert p1.toString() == p2.toString()

includeProperties

True

Should properties be included in tuple constructor generation

import groovy.transform.TupleConstructor

@TupleConstructor(includeProperties=false)
class Person {
    String firstName
    String lastName
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')

try {
    def p2 = new Person('Jack', 'Nicholson')
} catch(e) {
    // will fail because properties are not included
}

includeSuperFields

False

Should fields from super classes be included in tuple constructor generation

import groovy.transform.TupleConstructor

class Base {
    protected String occupation
    public String occupation() { this.occupation }
}

@TupleConstructor(includeSuperFields=true)
class Person extends Base {
    String firstName
    String lastName
    public String toString() {
        "$firstName $lastName: ${occupation()}"
    }
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson', occupation: 'Actor')

def p2 = new Person('Actor', 'Jack', 'Nicholson')

assert p1.firstName == p2.firstName
assert p1.lastName == p2.lastName
assert p1.toString() == 'Jack Nicholson: Actor'
assert p2.toString() == p1.toString()

includeSuperProperties

True

Should properties from super classes be included in tuple constructor generation

import groovy.transform.TupleConstructor

class Base {
    String occupation
}

@TupleConstructor(includeSuperProperties=true)
class Person extends Base {
    String firstName
    String lastName
    public String toString() {
        "$firstName $lastName: $occupation"
    }
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')

def p2 = new Person('Actor', 'Jack', 'Nicholson')

assert p1.firstName == p2.firstName
assert p1.lastName == p2.lastName
assert p1.toString() == 'Jack Nicholson: null'
assert p2.toString() == 'Jack Nicholson: Actor'

callSuper

False

Should super properties be called within a call to the parent constructor rather than set as properties

import groovy.transform.TupleConstructor

class Base {
    String occupation
    Base() {}
    Base(String job) { occupation = job?.toLowerCase() }
}

@TupleConstructor(includeSuperProperties = true, callSuper=true)
class Person extends Base {
    String firstName
    String lastName
    public String toString() {
        "$firstName $lastName: $occupation"
    }
}

def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')

def p2 = new Person('ACTOR', 'Jack', 'Nicholson')

assert p1.firstName == p2.firstName
assert p1.lastName == p2.lastName
assert p1.toString() == 'Jack Nicholson: null'
assert p2.toString() == 'Jack Nicholson: actor'

force

False

By default, the transformation will do nothing if a constructor is already defined. Setting this property to true, the constructor will be generated and it’s your responsibility to ensure that no duplicate constructor is defined

See javadocs

@groovy.transform.Canonical

The @Canonical AST transformation combines the effects of the @ToString, @EqualsAndHashCode and @TupleConstructor annotations:

import groovy.transform.Canonical

@Canonical
class Person {
    String firstName
    String lastName
}
def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p1.toString() == 'Person(Jack, Nicholson)' // Effect of @ToString

def p2 = new Person('Jack','Nicholson') // Effect of @TupleConstructor
assert p2.toString() == 'Person(Jack, Nicholson)'

assert p1==p2 // Effect of @EqualsAndHashCode
assert p1.hashCode()==p2.hashCode() // Effect of @EqualsAndHashCode

A similar immutable class can be generated using the @Immutable AST transformation instead. The @Canonical AST transformation supports several configuration options:

Attribute Default value Description Example

excludes

Empty list

List of properties to exclude from tuple constructor generation

import groovy.transform.Canonical

@Canonical(excludes=['lastName'])
class Person {
    String firstName
    String lastName
}
def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p1.toString() == 'Person(Jack)' // Effect of @ToString

def p2 = new Person('Jack') // Effect of @TupleConstructor
assert p2.toString() == 'Person(Jack)'

assert p1==p2 // Effect of @EqualsAndHashCode
assert p1.hashCode()==p2.hashCode() // Effect of @EqualsAndHashCode

includes

Empty list

List of fields to include in tuple constructor generation

import groovy.transform.Canonical

@Canonical(includes=['firstName'])
class Person {
    String firstName
    String lastName
}
def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
assert p1.toString() == 'Person(Jack)' // Effect of @ToString

def p2 = new Person('Jack') // Effect of @TupleConstructor
assert p2.toString() == 'Person(Jack)'

assert p1==p2 // Effect of @EqualsAndHashCode
assert p1.hashCode()==p2.hashCode() // Effect of @EqualsAndHashCode
@groovy.transform.InheritConstructors

The @InheritConstructor AST transformation aims at generating constructors matching super constructors for you. This is in particular useful when overriding exception classes:

import groovy.transform.InheritConstructors

@InheritConstructors
class CustomException extends Exception {}

// all those are generated constructors
new CustomException()
new CustomException("A custom message")
new CustomException("A custom message", new RuntimeException())
new CustomException(new RuntimeException())

// Java 7 only
// new CustomException("A custom message", new RuntimeException(), false, true)

The @InheritConstructor AST transformation supports the following configuration options:

Attribute Default value Description Example

constructorAnnotations

False

Whether to carry over annotations from the constructor during copying

@Retention(RetentionPolicy.RUNTIME)
@Target([ElementType.CONSTRUCTOR])
public @interface ConsAnno {}

class Base {
  @ConsAnno Base() {}
}

@InheritConstructors(constructorAnnotations=true)
class Child extends Base {}

assert Child.constructors[0].annotations[0].annotationType().name == 'ConsAnno'

parameterAnnotations

False

Whether to carry over annotations from the constructor parameters when copying the constructor

@Retention(RetentionPolicy.RUNTIME)
@Target([ElementType.PARAMETER])
public @interface ParamAnno {}

class Base {
  Base(@ParamAnno String name) {}
}

@InheritConstructors(parameterAnnotations=true)
class Child extends Base {}

assert Child.constructors[0].parameterAnnotations[0][0].annotationType().name == 'ParamAnno'
@groovy.lang.Category

The @Category AST transformation simplifies the creation of Groovy categories. Historically, a Groovy category was written like this:

class TripleCategory {
    public static Integer triple(Integer self) {
        3*self
    }
}
use (TripleCategory) {
    assert 9 == 3.triple()
}

The @Category transformation lets you write the same using an instance-style class, rather than a static class style. This removes the need for having the first argument of each method being the receiver. The category can be written like this:

@Category(Integer)
class TripleCategory {
    public Integer triple() { 3*this }
}
use (TripleCategory) {
    assert 9 == 3.triple()
}

Note that the mixed in class can be referenced using this instead. It’s also worth noting that using instance fields in a category class is inherently unsafe: categories are not stateful (like traits).

@groovy.transform.IndexedProperty

The @IndexedProperty annotation aims at generating indexed getters/setters for properties of list/array types. This is in particular useful if you want to use a Groovy class from Java. While Groovy supports GPath to access properties, this is not available from Java. The @IndexedProperty annotation will generate indexed properties of the following form:

class SomeBean {
    @IndexedProperty String[] someArray = new String[2]
    @IndexedProperty List someList = []
}

def bean = new SomeBean()
bean.setSomeArray(0, 'value')
bean.setSomeList(0, 123)

assert bean.someArray[0] == 'value'
assert bean.someList == [123]
@groovy.lang.Lazy

The @Lazy AST transformation implements lazy initialization of fields. For example, the following code:

class SomeBean {
    @Lazy LinkedList myField
}

will produce the following code:

List $myField
List getMyField() {
    if ($myField!=null) { return $myField }
    else {
        $myField = new LinkedList()
        return $myField
    }
}

The default value which is used to initialize the field is the default constructor of the declaration type. It is possible to define a default value by using a closure on the right hand side of the property assignment, as in the following example:

class SomeBean {
    @Lazy LinkedList myField = { ['a','b','c']}()
}

In that case, the generated code looks like the following:

List $myField
List getMyField() {
    if ($myField!=null) { return $myField }
    else {
        $myField = { ['a','b','c']}()
        return $myField
    }
}

If the field is declared volatile then initialization will be synchronized using the double-checked locking pattern.

Using the soft=true parameter, the helper field will use a SoftReference instead, providing a simple way to implement caching. In that case, if the garbage collector decides to collect the reference, initialization will occur the next time the field is accessed.

@groovy.lang.Newify

The @Newify AST transformation is used to bring alternative syntaxes to construct objects:

  • Using the Python style:

@Newify([Tree,Leaf])
class TreeBuilder {
    Tree tree = Tree(Leaf('A'),Leaf('B'),Tree(Leaf('C')))
}
  • or using the Ruby style:

@Newify([Tree,Leaf])
class TreeBuilder {
    Tree tree = Tree.new(Leaf.new('A'),Leaf.new('B'),Tree.new(Leaf.new('C')))
}

The Ruby version can be disabled by setting the auto flag to false.

@groovy.transform.Sortable

The @Sortable AST transformation is used to help write classes that are Comparable and easily sorted by numerous properties. It is easy to use as shown in the following example where we annotate the Person class:

import groovy.transform.Sortable

@Sortable class Person {
    String first
    String last
    Integer born
}

The generated class has the following properties:

  • it implements the Comparable interface

  • it contains a compareTo method with an implementation based on the natural ordering of the first, last and born properties

  • it has three methods returning comparators: comparatorByFirst, comparatorByLast and comparatorByBorn.

The generated compareTo method will look like this:

public int compareTo(java.lang.Object obj) {
    if (this.is(obj)) {
        return 0
    }
    if (!(obj instanceof Person)) {
        return -1
    }
    java.lang.Integer value = this.first <=> obj.first
    if (value != 0) {
        return value
    }
    value = this.last <=> obj.last
    if (value != 0) {
        return value
    }
    value = this.born <=> obj.born
    if (value != 0) {
        return value
    }
    return 0
}

As an example of the generated comparators, the comparatorByFirst comparator will have a compare method that looks like this:

public int compare(java.lang.Object arg0, java.lang.Object arg1) {
    if (arg0 == arg1) {
        return 0
    }
    if (arg0 != null && arg1 == null) {
        return -1
    }
    if (arg0 == null && arg1 != null) {
        return 1
    }
    return arg0.first <=> arg1.first
}

The Person class can be used wherever a Comparable is expected and the generated comparators wherever a Comparator is expected as shown by these examples:

def people = [
    new Person(first: 'Johnny', last: 'Depp', born: 1963),
    new Person(first: 'Keira', last: 'Knightley', born: 1985),
    new Person(first: 'Geoffrey', last: 'Rush', born: 1951),
    new Person(first: 'Orlando', last: 'Bloom', born: 1977)
]

assert people[0] > people[2]
assert people.sort()*.last == ['Rush', 'Depp', 'Knightley', 'Bloom']
assert people.sort(false, Person.comparatorByFirst())*.first == ['Geoffrey', 'Johnny', 'Keira', 'Orlando']
assert people.sort(false, Person.comparatorByLast())*.last == ['Bloom', 'Depp', 'Knightley', 'Rush']
assert people.sort(false, Person.comparatorByBorn())*.last == ['Rush', 'Depp', 'Bloom', 'Knightley']

Normally, all properties are used in the generated compareTo method in the priority order in which they are defined. You can include or exclude certain properties from the generated compareTo method by giving a list of property names in the includes or excludes annotation attributes. If using includes, the order of the property names given will determine the priority of properties when comparing. To illustrate, consider the following Person class definition:

@Sortable(includes='first,born') class Person {
    String last
    int born
    String first
}

It will have two comparator methods comparatorByFirst and comparatorByBorn and the generated compareTo method will look like this:

public int compareTo(java.lang.Object obj) {
    if (this.is(obj)) {
        return 0
    }
    if (!(obj instanceof Person)) {
        return -1
    }
    java.lang.Integer value = this.first <=> obj.first
    if (value != 0) {
        return value
    }
    value = this.born <=> obj.born
    if (value != 0) {
        return value
    }
    return 0
}

This Person class can be used as follows:

def people = [
    new Person(first: 'Ben', last: 'Affleck', born: 1972),
    new Person(first: 'Ben', last: 'Stiller', born: 1965)
]

assert people.sort()*.last == ['Stiller', 'Affleck']
@groovy.transform.builder.Builder

The @Builder AST transformation is used to help write classes that can be created using fluent api calls. The transform supports multiple building strategies to cover a range of cases and there are a number of configuration options to customize the building process. If you’re an AST hacker, you can also define your own strategy class. The following table lists the available strategies that are bundled with Groovy and the configuration options each strategy supports.

Strategy

Description

builderClassName

builderMethodName

buildMethodName

prefix

includes/excludes

SimpleStrategy

chained setters

n/a

n/a

n/a

yes, default "set"

yes

ExternalStrategy

explicit builder class, class being built untouched

n/a

n/a

yes, default "build"

yes, default ""

yes

DefaultStrategy

creates a nested helper class

yes, default <TypeName>Builder

yes, default "builder"

yes, default "build"

yes, default ""

yes

InitializerStrategy

creates a nested helper class providing type-safe fluent creation

yes, default <TypeName>Initializer

yes, default "createInitializer"

yes, default "create" but usually only used internally

yes, default ""

yes

SimpleStrategy

To use the SimpleStrategy, annotate your Groovy class using the @Builder annotation, and specify the strategy as shown in this example:

import groovy.transform.builder.*

@Builder(builderStrategy=SimpleStrategy)
class Person {
    String first
    String last
    Integer born
}

Then, just call the setters in a chained fashion as shown here:

def p1 = new Person().setFirst('Johnny').setLast('Depp').setBorn(1963)
assert "$p1.first $p1.last" == 'Johnny Depp'

For each property, a generated setter will be created which looks like this:

public Person setFirst(java.lang.String first) {
    this.first = first
    return this
}

You can specify a prefix as shown in this example:

import groovy.transform.builder.*

@Builder(builderStrategy=SimpleStrategy, prefix="")
class Person {
    String first
    String last
    Integer born
}

And calling the chained setters would look like this:

def p = new Person().first('Johnny').last('Depp').born(1963)
assert "$p.first $p.last" == 'Johnny Depp'

You can use the SimpleStrategy in conjunction with @Canonical. If your @Builder annotation doesn’t have explicit includes or excludes annotation attributes but your @Canonical annotation does, the ones from @Canonical will be re-used for @Builder.

The annotation attributes builderClassName, buildMethodName, builderMethodName and forClass are not supported for this strategy.

Groovy already has built-in building mechanisms. Don’t rush to using @Builder if the built-in mechanisms meet your needs. Some examples:
def p2 = new Person(first: 'Keira', last: 'Knightley', born: 1985)
def p3 = new Person().with {
    first = 'Geoffrey'
    last = 'Rush'
    born = 1951
}
ExternalStrategy

To use the ExternalStrategy, create and annotate a Groovy builder class using the @Builder annotation, specify the class the builder is for using forClass and indicate use of the ExternalStrategy. Suppose you have the following class you would like a builder for:

class Person {
    String first
    String last
    int born
}

you explicitly create and use your builder class as follows:

import groovy.transform.builder.*

@Builder(builderStrategy=ExternalStrategy, forClass=Person)
class PersonBuilder { }

def p = new PersonBuilder().first('Johnny').last('Depp').born(1963).build()
assert "$p.first $p.last" == 'Johnny Depp'

Note that the (normally empty) builder class you provide will be filled in with appropriate setters and a build method. The generated build method will look something like:

public Person build() {
    Person _thePerson = new Person()
    _thePerson.first = first
    _thePerson.last = last
    _thePerson.born = born
    return _thePerson
}

The class you are creating the builder for can be any Java or Groovy class following the normal JavaBean conventions, e.g. a no-arg constructor and setters for the properties. Here is an example using a Java class:

import groovy.transform.builder.*

@Builder(builderStrategy=ExternalStrategy, forClass=javax.swing.DefaultButtonModel)
class ButtonModelBuilder {}

def model = new ButtonModelBuilder().enabled(true).pressed(true).armed(true).rollover(true).selected(true).build()
assert model.isArmed()
assert model.isPressed()
assert model.isEnabled()
assert model.isSelected()
assert model.isRollover()

The generated builder can be customised using the prefix, includes, excludes and buildMethodName annotation attributes. Here is an example illustrating various customisations:

import groovy.transform.builder.*
import groovy.transform.Canonical

@Canonical
class Person {
    String first
    String last
    int born
}

@Builder(builderStrategy=ExternalStrategy, forClass=Person, includes=['first', 'last'], buildMethodName='create', prefix='with')
class PersonBuilder { }

def p = new PersonBuilder().withFirst('Johnny').withLast('Depp').create()
assert "$p.first $p.last" == 'Johnny Depp'

The builderMethodName and builderClassName annotation attributes for @Builder aren’t applicable for this strategy.

You can use the ExternalStrategy in conjunction with @Canonical. If your @Builder annotation doesn’t have explicit includes or excludes annotation attributes but the @Canonical annotation of the class you are creating the builder for does, the ones from @Canonical will be re-used for @Builder.

DefaultStrategy

To use the DefaultStrategy, annotate your Groovy class using the @Builder annotation as shown in this example:

import groovy.transform.builder.Builder

@Builder
class Person {
    String firstName
    String lastName
    int age
}

def person = Person.builder().firstName("Robert").lastName("Lewandowski").age(21).build()
assert person.firstName == "Robert"
assert person.lastName == "Lewandowski"
assert person.age == 21

If you want, you can customize various aspects of the building process using the builderClassName, buildMethodName, builderMethodName, prefix, includes and excludes annotation attributes, some of which are used in the example here:

import groovy.transform.builder.Builder

@Builder(buildMethodName='make', builderMethodName='maker', prefix='with', excludes='age')
class Person {
    String firstName
    String lastName
    int age
}

def p = Person.maker().withFirstName("Robert").withLastName("Lewandowski").make()
assert "$p.firstName $p.lastName" == "Robert Lewandowski"

This strategy also supports annotating static methods and constructors. In this case, the static method or constructor parameters become the properties to use for building purposes and in the case of static methods, the return type of the method becomes the target class being built. If you have more than one @Builder annotation used within a class (at either the class, method or constructor positions) then it is up to you to ensure that the generated helper classes and factory methods have unique names (i.e. no more than one can use the default name values). Here is an example highlighting method and constructor usage (and also illustrating the renaming required for unique names).

import groovy.transform.builder.*
import groovy.transform.*

@ToString
@Builder
class Person {
  String first, last
  int born

  Person(){}

  @Builder(builderClassName='MovieBuilder', builderMethodName='byRoleBuilder')
  Person(String roleName) {
     if (roleName == 'Jack Sparrow') {
         this.first = 'Johnny'; this.last = 'Depp'; this.born = 1963
     }
  }

  @Builder(builderClassName='NameBuilder', builderMethodName='nameBuilder', prefix='having', buildMethodName='fullName')
  static String join(String first, String last) {
      first + ' ' + last
  }

  @Builder(builderClassName='SplitBuilder', builderMethodName='splitBuilder')
  static Person split(String name, int year) {
      def parts = name.split(' ')
      new Person(first: parts[0], last: parts[1], born: year)
  }
}

assert Person.splitBuilder().name("Johnny Depp").year(1963).build().toString() == 'Person(Johnny, Depp, 1963)'
assert Person.byRoleBuilder().roleName("Jack Sparrow").build().toString() == 'Person(Johnny, Depp, 1963)'
assert Person.nameBuilder().havingFirst('Johnny').havingLast('Depp').fullName() == 'Johnny Depp'
assert Person.builder().first("Johnny").last('Depp').born(1963).build().toString() == 'Person(Johnny, Depp, 1963)'

The forClass annotation attribute is not supported for this strategy.

InitializerStrategy

To use the InitializerStrategy, annotate your Groovy class using the @Builder annotation, and specify the strategy as shown in this example:

import groovy.transform.builder.*
import groovy.transform.*

@ToString
@Builder(builderStrategy=InitializerStrategy)
class Person {
    String firstName
    String lastName
    int age
}

Your class will be locked down to have a single public constructor taking a "fully set" initializer. It will also have a factory method to create the initializer. These are used as follows:

@CompileStatic
def firstLastAge() {
    assert new Person(Person.createInitializer().firstName("John").lastName("Smith").age(21)).toString() == 'Person(John, Smith, 21)'
}
firstLastAge()

Any attempt to use the initializer which doesn’t involve setting all the properties (though order is not important) will result in a compilation error. If you don’t need this level of strictness, you don’t need to use @CompileStatic.

You can use the InitializerStrategy in conjunction with @Canonical and @Immutable. If your @Builder annotation doesn’t have explicit includes or excludes annotation attributes but your @Canonical annotation does, the ones from @Canonical will be re-used for @Builder. Here is an example using @Builder with @Immutable:

import groovy.transform.builder.*
import groovy.transform.*

@Builder(builderStrategy=InitializerStrategy)
@Immutable
class Person {
    String first
    String last
    int born
}

@CompileStatic
def createFirstLastBorn() {
  def p = new Person(Person.createInitializer().first('Johnny').last('Depp').born(1963))
  assert "$p.first $p.last $p.born" == 'Johnny Depp 1963'
}

createFirstLastBorn()

This strategy also supports annotating static methods and constructors. In this case, the static method or constructor parameters become the properties to use for building purposes and in the case of static methods, the return type of the method becomes the target class being built. If you have more than one @Builder annotation used within a class (at either the class, method or constructor positions) then it is up to you to ensure that the generated helper classes and factory methods have unique names (i.e. no more than one can use the default name values). For an example of method and constructor usage but using the DefaultStrategy strategy, consult that strategy’s documentation.

The annotation attribute forClass is not supported for this strategy.

Class design annotations

This category of annotations are aimed at simplifying the implementation of well-known design patterns (delegation, singleton, …​) by using a declarative style.

@groovy.lang.Delegate

The @Delegate AST transformation aims at implementing the delegation design pattern. In the following class:

class Event {
    @Delegate Date when
    String title
}

The when field is annotated with @Delegate, meaning that the Event class will delegate calls to Date methods to the when field. In this case, the generated code looks like this:

class Event {
    Date when
    String title
    boolean before(Date other) {
        when.before(other)
    }
    // ...
}

Then you can call the before method, for example, directly on the Event class:

def ev = new Event(title:'Groovy keynote', when: Date.parse('yyyy/MM/dd', '2013/09/10'))
def now = new Date()
assert ev.before(now)

The behavior of the @Delegate AST transformation can be changed using the following parameters:

Attribute Default value Description Example

interfaces

True

Should the interfaces implemented by the field be implemented by the class too

interface Greeter { void sayHello() }
class MyGreeter implements Greeter { void sayHello() { println 'Hello!'} }

class DelegatingGreeter { // no explicit interface
    @Delegate MyGreeter greeter = new MyGreeter()
}
def greeter = new DelegatingGreeter()
assert greeter instanceof Greeter // interface was added transparently

deprecated

false

If true, also delegates methods annotated with @Deprecated

class WithDeprecation {
    @Deprecated
    void foo() {}
}
class WithoutDeprecation {
    @Deprecated
    void bar() {}
}
class Delegating {
    @Delegate(deprecated=true) WithDeprecation with = new WithDeprecation()
    @Delegate WithoutDeprecation without = new WithoutDeprecation()
}
def d = new Delegating()
d.foo() // passes thanks to deprecated=true
d.bar() // fails because of @Deprecated

methodAnnotations

False

Whether to carry over annotations from the methods of the delegate to your delegating method.

class WithAnnotations {
    @Transactional
    void method() {
    }
}
class DelegatingWithoutAnnotations {
    @Delegate WithAnnotations delegate
}
class DelegatingWithAnnotations {
    @Delegate(methodAnnotations = true) WithAnnotations delegate
}
def d1 = new DelegatingWithoutAnnotations()
def d2 = new DelegatingWithAnnotations()
assert d1.class.getDeclaredMethod('method').annotations.length==0
assert d2.class.getDeclaredMethod('method').annotations.length==1

parameterAnnotations

False

Whether to carry over annotations from the method parameters of the delegate to your delegating method.

class WithAnnotations {
    void method(@NotNull String str) {
    }
}
class DelegatingWithoutAnnotations {
    @Delegate WithAnnotations delegate
}
class DelegatingWithAnnotations {
    @Delegate(parameterAnnotations = true) WithAnnotations delegate
}
def d1 = new DelegatingWithoutAnnotations()
def d2 = new DelegatingWithAnnotations()
assert d1.class.getDeclaredMethod('method',String).parameterAnnotations[0].length==0
assert d2.class.getDeclaredMethod('method',String).parameterAnnotations[0].length==1

excludes

Empty array

A list of methods to be excluded from delegation. For more fine-grained control, see also excludeTypes.

class Worker {
    void task1() {}
    void task2() {}
}
class Delegating {
    @Delegate(excludes=['task2']) Worker worker = new Worker()
}
def d = new Delegating()
d.task1() // passes
d.task2() // fails because method is excluded

includes

Empty array

A list of methods to be included in delegation. For more fine-grained control, see also includeTypes.

class Worker {
    void task1() {}
    void task2() {}
}
class Delegating {
    @Delegate(includes=['task1']) Worker worker = new Worker()
}
def d = new Delegating()
d.task1() // passes
d.task2() // fails because method is not included

excludeTypes

Empty array

A list of interfaces containing method signatures to be excluded from delegation

interface AppendStringSelector {
    StringBuilder append(String str)
}
class UpperStringBuilder {
    @Delegate(excludeTypes=AppendStringSelector)
    StringBuilder sb1 = new StringBuilder()

    @Delegate(includeTypes=AppendStringSelector)
    StringBuilder sb2 = new StringBuilder()

    String toString() { sb1.toString() + sb2.toString().toUpperCase() }
}
def usb = new UpperStringBuilder()
usb.append(3.5d)
usb.append('hello')
usb.append(true)
assert usb.toString() == '3.5trueHELLO'

includeTypes

Empty array

A list of interfaces containing method signatures to be included in delegation

interface AppendBooleanSelector {
    StringBuilder append(boolean b)
}
interface AppendFloatSelector {
    StringBuilder append(float b)
}
class NumberBooleanBuilder {
    @Delegate(includeTypes=AppendBooleanSelector, interfaces=false)
    StringBuilder nums = new StringBuilder()
    @Delegate(includeTypes=[AppendFloatSelector], interfaces=false)
    StringBuilder bools = new StringBuilder()
    String result() { "${nums.toString()}
@groovy.transform.Immutable

The @Immutable AST transformation simplifies the creation of immutable classes, that is to say classes for which members are deemed immutable. For that, all you have to do is annotating the class like in the following example:

import groovy.transform.Immutable

@Immutable
class Point {
    int x
    int y
}

Immutable classes generated with @Immutable are automatically made final. For a class to be immutable, you have to make sure that properties are of an immutable type (primitive or boxed types), of a known-immutable type or another class annotated with @Immutable. The effect of applying @Immutable to a class are pretty similar to those of applying the @Canonical AST transformation, but with an immutable class: automatic generation of toString, equals and hashCode methods for example, but trying to modify a property would throw a ReadOnlyPropertyException in that case.

Since @Immutable relies on a predefined list of known immutable classes (like java.net.URI or java.lang.String and fails if you use a type which is not in that list, you are allowed to instruct the transformation that some types are deemed immutable thanks to the following parameters:

Attribute Default value Description Example

knownImmutableClasses

Empty list

A list of classes which are deemed immutable.

import groovy.transform.Immutable
import groovy.transform.TupleConstructor

@TupleConstructor
final class Point {
    final int x
    final int y
    public String toString() { "($x,$y)" }
}

@Immutable(knownImmutableClasses=[Point])
class Triangle {
    Point a,b,c
}

knownImmutables

Empty list

A list of property names which are deemed immutable.

import groovy.transform.Immutable
import groovy.transform.TupleConstructor

@TupleConstructor
final class Point {
    final int x
    final int y
    public String toString() { "($x,$y)" }
}

@Immutable(knownImmutables=['a','b','c'])
class Triangle {
    Point a,b,c
}

copyWith

false

A boolean whether to generate a copyWith( Map ) method.

import groovy.transform.Immutable

@Immutable( copyWith=true )
class User {
    String  name
    Integer age
}

def bob   = new User( 'bob', 43 )
def alice = bob.copyWith( name:'alice' )
assert alice.name == 'alice'
assert alice.age  == 43
@groovy.transform.Memoized

The @Memoized AST transformations simplifies the implementation of caching by allowing the result of method calls to be cached just by annotating the method with @Memoized. Let’s imagine the following method:

long longComputation(int seed) {
    // slow computation
    Thread.sleep(1000*seed)
    System.nanoTime()
}

This emulates a long computation, based on the actual parameters of the method. Without @Memoized, each method call would take several seconds plus it would return a random result:

def x = longComputation(1)
def y = longComputation(1)
assert x!=y

Adding @Memoized changes the semantics of the method by adding caching, based on the parameters:

@Memoized
long longComputation(int seed) {
    // slow computation
    Thread.sleep(1000*seed)
    System.nanoTime()
}

def x = longComputation(1) // returns after 1 second
def y = longComputation(1) // returns immediatly
def z = longComputation(2) // returns after 2 seconds
assert x==y
assert x!=z

The size of the cache can be configured using two optional parameters:

  • protectedCacheSize: the number of results which are guaranteed not to be cleared after garbage collection

  • maxCacheSize: the maximum number of results that can be kept in memory

By default, the size of the cache is unlimited and no cache result is protected from garbage collection. Setting a protectedCacheSize>0 would create an unlimited cache with some results protected. Setting maxCacheSize>0 would create a limited cache but without any protection from garbage protection. Setting both would create a limited, protected cache.

@groovy.lang.Singleton

The @Singleton annotation can be used to implement the singleton design pattern on a class. The singleton instance is defined eagerly by default, using class initialization, or lazily, in which case the field is initialized using double checked locking.

@Singleton
class GreetingService {
    String greeting(String name) { "Hello, $name!" }
}
assert GreetingService.instance.greeting('Bob') == 'Hello, Bob!'

By default, the singleton is created eagerly when the class is initialized and available through the instance property. It is possible to change the name of the singleton using the property parameter:

@Singleton(property='theOne')
class GreetingService {
    String greeting(String name) { "Hello, $name!" }
}

assert GreetingService.theOne.greeting('Bob') == 'Hello, Bob!'

And it is also possible to make initialization lazy using the lazy parameter:

class Collaborator {
    public static boolean init = false
}
@Singleton(lazy=true,strict=false)
class GreetingService {
    static void init() {}
    GreetingService() {
        Collaborator.init = true
    }
    String greeting(String name) { "Hello, $name!" }
}
GreetingService.init() // make sure class is initialized
assert Collaborator.init == false
GreetingService.instance
assert Collaborator.init == true
assert GreetingService.instance.greeting('Bob') == 'Hello, Bob!'

In this example, we also set the strict parameter to false, which allows us to define our own constructor.

@groovy.transform.Mixin

Deprecated. Consider using traits instead.

Logging improvements

Groovy provides AST transformation that helps integrating with the most widely used logging frameworks. It’s worth noting that annotating a class with one of those annotations doesn’t prevent you from adding the appropriate logging framework on classpath.

All transformations work in a similar way:

  • add static final log field corresponding to the logger

  • wrap all calls to log.level() into the appropriate log.isLevelEnabled guard, depending on the underlying framework

Those transformations support two parameters:

  • value (default log) corresponds to the name of the logger field

  • category (defaults to the class name) is the name of the logger category

@groovy.util.logging.Log

The first logging AST transformation available is the @Log annotation which relies on the JDK logging framework. Writing:

@groovy.util.logging.Log
class Greeter {
    void greet() {
        log.info 'Called greeter'
        println 'Hello, world!'
    }
}

is equivalent to writing:

import java.util.logging.Level
import java.util.logging.Logger

class Greeter {
    private static final Logger log = Logger.getLogger(Greeter.name)
    void greet() {
        if (log.isLoggable(Level.INFO)) {
            log.info 'Called greeter'
        }
        println 'Hello, world!'
    }
}
@groovy.util.logging.Commons

Groovy supports the Apache Commons Logging framework using to the @Commons annotation. Writing:

@groovy.util.logging.Commons
class Greeter {
    void greet() {
        log.debug 'Called greeter'
        println 'Hello, world!'
    }
}

is equivalent to writing:

import org.apache.commons.logging.LogFactory
import org.apache.commons.logging.Log

class Greeter {
    private static final Log log = LogFactory.getLog(Greeter)
    void greet() {
        if (log.isDebugEnabled()) {
            log.debug 'Called greeter'
        }
        println 'Hello, world!'
    }
}
@groovy.util.logging.Log4j

Groovy supports the Apache Log4j 1.x framework using to the @Log4j annotation. Writing:

@groovy.util.logging.Log4j
class Greeter {
    void greet() {
        log.debug 'Called greeter'
        println 'Hello, world!'
    }
}

is equivalent to writing:

import org.apache.log4j.Logger

class Greeter {
    private static final Logger log = Logger.getLogger(Greeter)
    void greet() {
        if (log.isDebugEnabled()) {
            log.debug 'Called greeter'
        }
        println 'Hello, world!'
    }
}
@groovy.util.logging.Log4j2

Groovy supports the Apache Log4j 2.x framework using to the @Log4j2 annotation. Writing:

@groovy.util.logging.Log4j2
class Greeter {
    void greet() {
        log.debug 'Called greeter'
        println 'Hello, world!'
    }
}

is equivalent to writing:

import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger

class Greeter {
    private static final Logger log = LogManager.getLogger(Greeter)
    void greet() {
        if (log.isDebugEnabled()) {
            log.debug 'Called greeter'
        }
        println 'Hello, world!'
    }
}
@groovy.util.logging.Slf4j

Groovy supports the Simple Logging Facade for Java (SLF4J) framework using to the @Slf4j annotation. Writing:

@groovy.util.logging.Slf4j
class Greeter {
    void greet() {
        log.debug 'Called greeter'
        println 'Hello, world!'
    }
}

is equivalent to writing:

import org.slf4j.LoggerFactory
import org.slf4j.Logger

class Greeter {
    private static final Logger log = LoggerFactory.getLogger(Greeter)
    void greet() {
        if (log.isDebugEnabled()) {