Release notes for Groovy 2.3

Groovy 2.3 is the new major release of Groovy, featuring official support for running Groovy on JDK 8, traits, new and improved AST transformations like @TailRecursive, @Builder and @Sortable, a new NIO2 module with Path support, lightening fast JSON parsing and building,closure parameter type inference, a new markup template engine, Groovysh and GroovyConsole ease of use improvements, a new GroovyAssert test utility, more @BaseScript class capabilities, and more.

Official support for running Groovy on JDK 8

This is the first version of Groovy to be officially compatible with JDK 8.

JDK 8 and its interface default methods introduced some incompatibilities with a few methods of the Groovy Development Kit, so we had to adapt to the situation, introducing minor breaking changes for the affected methods and their outcome.

Note that we’re not planning to backport the changes to older versions of Groovy, so if you want to run Groovy on JDK 8, you’ll have to upgrade to the shiniest version of Groovy!

Groovy 2.3 doesn’t support the new syntax constructs offered by Java 8 (such as lambdas, method references, default methods in interfaces, etc.), but you can very well already use the new APIs offered by JDK 8, and even use Groovy closures in lieu of Java 8 lambdas.

For reference, here are a couple of examples which use Java 8 streams, for iterating over a stream of ints, or over the lines of a file:

IntStream.range(1, 100).forEach { println it }

Files.lines(Paths.get('README.adoc'))
     .map { it.toUpperCase() }
     .forEach { println it }

In particular, in the two statements above, notice that we replaced Java 8 lambdas with Groovy closures, as Groovy provides a closure coercion mechanism which transforms a Groovy closure into a functional interface — unlike Java, Groovy also provides that coercion mechanism for abstract classes containing a single abstract method.

In future versions of Groovy, certain Java 8 syntax constructs, or particular Groovy methods decorating JDK 8 APIs might be added.

Traits

A major highlight for Groovy 2.3 is the introduction of the concept of traits.

Traits are reusable components of behavior that your classes can implement, and are an additional Object-Oriented concept alongside classes and interfaces.

Below, we create a trait with a concrete method fly() which returns a String.

trait FlyingAbility {
    String fly() { "I'm flying!" }
}

Then we create a class, Bird, that implements that trait, and instantiate it:

class Bird implements FlyingAbility {}
def b = new Bird()

We can check that the Bird instance does have the new fly() method mixed-in:

assert b.fly() == "I'm flying!"

Groovy traits are stateful (unlike Java 8 interface default methods). A trait can have Groovy properties like plain classes:

trait Named {
    String name
}

This time, the Bird class implements that Named trait:

class Bird implements Named {}

We can instantiate the Bird with the named-argument constructor shortcut provided by Groovy:

def b = new Bird(name: 'Colibri')

We assert that the instantiated Bird does have the name property added to it:

assert b.name == 'Colibri'

They allow the composition of behavior without going into the "diamond inheritance" problem allowing you to decide which behavior prevails upon conflict, either by convention (last trait declared wins) or by explicitly overriding the conflicting method:

trait KiteSurfer { String surf() { 'kite' } }

trait WebSurfer  { String surf() {  'web' } }

class Person { String name }

class Hipster extends Person
           implements KiteSurfer, WebSurfer {}

def h = new Hipster()
assert h.surf() == 'web'

Above, the surf() method from WebSurfer wins, as it’s the last declared trait, but you can reverse the trait implementation order if you want kite to be returned. If you want to be more explicit, your Hipster class can override the surf() method itself, and call WebSurfer.super.foo() or KiteSurfer.super.foo() or do something entirely different.

Traits support inheritance, thus a trait can extend another trait or implement an interface, as shown below:

trait Named { String name }

trait FlyingAbility extends Named {
    String fly() { "I'm a flying ${name}!" }
}

class Bird implements FlyingAbility {}
def b = new Bird(name: 'Colibri')

assert b.name == 'Colibri'
assert b.fly() == "I'm a flying Colibri!"

Traits are compatible with static type checking and compilation, as well as our usual dynamic behavior. Trait mixed-in methods are actually "real" methods (i.e. visible from Java as well) and not just dynamic. Note however, that not all existing AST transformations are compatible with traits.

Traits can also be implemented at runtime with as or with withTraits if you just want to add behavior of a trait to an object you’re instantiating, without having to create an intermediary artificial class just for that purpose (also called per-instance traits):

trait Named { String name }

trait Quacks {
    String quack() { 'Quack!' }
}

class Animal {}

def na = new Animal().withTraits Named, Quacks
na.name = 'Daffy'
assert na.name == 'Daffy'
assert na.quack() == 'Quack!'

You can find more information on traits in the exhaustive traits documentation.

New and updated AST transformations

New transformations

@TailRecursive

@TailRecursive on methods adds tail recursion to methods which are recursive and call themselves at the last operation of the method body, which helps avoid blowing up the stack with the recursive calls (GROOVY-6570).

Here’s a slightly rewritten factorial implementation, that is friendly to tail-call transformation:

import groovy.transform.TailRecursive

@TailRecursive
def fact(BigInteger n, accu = 1G) {
    if (n < 2) accu
    else fact(n - 1, n * accu)
}

assert fact(1000) > 10e2566

@Builder

Recent Java APIs have adopted the builder pattern (not to be confused with Groovy’s builders) to instantiate complex objects, without requiring to multiply the number of constructors with variants taking various combination of parameters. Groovy 2.3 introduces a @Builder transformation to automate the creation of such builder APIs (GROOVY-6484).

The @Builder transformation offers different implementation strategies that you can choose from:

  • a simple strategy for creating chained setters

  • an external strategy where you annotate an explicit builder class while leaving some buildee class being built untouched

  • a default strategy which creates a nested helper class for instance creation

  • and an initializer strategy which creates a nested helper class for instance creation which when used with @CompileStatic allows type-safe object creation

Here’s an example with the default strategy:

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

You can have a look at the @Builder documentation for the other builder variants.

@Sortable

@Sortable on classes implements comparison methods for you (through implementing the Comparable interface), according to the declaration order of your properties (GROOVY-6649).

For the following Person class, its instances will be sorted by last name, then by first name, and by age, in that order:

import groovy.transform.*

@Sortable
@Canonical
class Person {
    String last
    String first
    int age
}

def folks = [
    new Person('Simpson', 'Bart', 12),
    new Person('Simpson', 'Homer', 40),
    new Person('Kent', 'Clark', 36)
]

assert folks.sort()*.first == ['Clark', 'Bart', 'Homer']

Additionally, you can define included / excluded fields, access individual field comparators with methods like comparatorByFirst().

More details on the @Sortable documentation page.

@SourceURI

With @SourceURI, you can annotate a java.net.URI or even a java.lang.String script variable or class field so that the variable or field are injected the URI of the Groovy file.

If you evaluate or compile a Groovy script or class, the variable or field will contain a data URI, for example, for the following example:

import groovy.transform.SourceURI

@SourceURI String src

println src

The src variable will contain the following data URI:

data:,import%20groovy.transform.SourceURI%0A%0A@SourceURI%20String%20src%0A%0Aprintln%20src

If you save the script in a file called sourceuri.groovy in /tmp, and run that script with the groovy command, you’ll see an absolute File path printed:

file:/tmp/sourceuri.groovy

As we mentioned above, you can also write @SourceURI URI src, if you want to have a URI instead of a String.

Updated transformations

@Delegate improvements

@Delegate supports includeTypes and excludeTypes attributes to give you fine-grained control over which methods to include or exclude from delegation. Rather than just matching on name, this option matches on the name and parameter types expressed in an interface type (GROOVY-6329).

@BaseScript class improvements

@BaseScript is a fairly recent addition in Groovy, and it allowed to annotate a variable in your script to instruct the compiler to use a particular base script class for this script. Now we have another notation which is nicer as you can annotate an import or a package (GROOVY-6592) to indicate that base script class:

@BaseScript(MyScript)
import groovy.transform.BaseScript

Additionally, base script classes can now use any abstract method for the script body. This means that you can implement the run() method to implement specific behavior like setup and tear down in tests (GROOVY-6585 and GROOVY-6615).

Given the following custom base script class, where we implement the default run() method, we also create a new abstract method called internalRun():

abstract class CustomBase extends Script {
    def run() {
        before()
        internalRun()
        after()
    }

    abstract internalRun()

    def before() { println 'before' }
    def after()  { println 'after'  }
}

We can then have the script below transparently implement the internalRun() method instead of the usual run() one:

import groovy.transform.BaseScript
@BaseScript CustomBase script

println 'Hello'

New NIO module for Java 7+

On JDK 7 and beyond, you can benefit from the same methods as the ones of File but for the new NIO2 class Path.

See GROOVY-6377 and the pull request for some further hints of the new methods.

You’ll find familiar methods of the Groovy GDK on File also available on Path like these:

path.withReader { Reader r -> ... }
path.eachLine { String line -> ... }
path.eachFileRecurse { Path p -> ... }
path << 'some content'
path << bytes
path.readLines()

Performance improvements

Miscellaneous improvements

Various minor performance improvements across the board, for static compilation, the invokedynamic backend, as well as "normal" dynamic Groovy, have been worked on.

Drastic JSON parsing and serialization performance improvements

Groovy JSON support has been refactored and tailored towards performance, making Groovy 2.3’s JSON support usually faster than all the JSON libraries available in the Java ecosystem.

Rick Hightower and Andrey Bleschestov covered the performance gains, both in parsing and serialization, in a benchmarks on Rick’s blog and on Andrey’s JSON benchmark project on GitHub. The results are impressive, as the parsing is generally roughly 2x to 4x faster with Groovy’s new parsers compared to existing libraries, and ~21x faster than pre-Groovy 2.3 parsing. On the serialization front, Groovy’s new serialization is also ~17x faster than before, and at the same level as competing libraries.

JSON slurper and builder enhancements

Beside the performance improvements of the JSON module, other updates have taken place.

With JsonSlurper, you’ll be able to set different parser types depending on the kind of input you wish to parse, particularly if you know the size of the payload you expect to parse, or whether you want a more tolerant parser which accepts elements like comments which are not normally supported by the JSON specification.

Here’s an example showing how to parse a non-conformant JSON payload:

import groovy.json.*
import static groovy.json.JsonParserType.*

def parser = new JsonSlurper().setType(LAX)

def conf = parser.parseText '''
    // configuration file
    {
        // no quote for key, single quoted value
        environment: 'production'
        # pound-style comment
        'server': 5
    }
'''

assert conf.environment == 'production'
assert conf.server == 5

Closure parameter type inference

We closed a gap which forced you to type your closure parameters to get correct type inference with static type checking or static compilation enabled. In situations like the following, you would have to explicitly give the type of the parameter, but it’s no longer required:

['a','b'].each { it.toUpperCase() }

In the signature of your methods taking closures as arguments, you’ll also be able to annotate the closure parameter with @ClosureParams to give additional hints to the type checker to infer the type of the parameters passed to your closure.

You can also find more about this in Cédric’s blog post on closure parameter type inference.

New markup template engine

Groovy now has an additional template engine, in the form of the Markup template engine, which gives you a very fast template engine (thanks to static compilation), based on the familiar Markup builder approach and notation, but also offering formatting options (indentation, escaping), internationalization, includes, as well as proposing type checked templates and models.

More details about the new Markup template engine in the documentation, as well as in Cédric’s blog, if you want to learn more about the "behind the scenes" stories!

To illustrate the basic usage, consider you have the following template:

def tpl = '''
    cars {
        cars.each {
            car(make: it.make, name: it.name)
        }
    }
'''

And have the following model:

model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota',  name: 'Prius')
]]

You would generate the following XML (or HTML) output:

<cars>
    <car make='Peugeot' name='508'/>
    <car make='Toyota'  name='Prius'/>
</cars>

By doing the following:

import groovy.text.markup.*

def config = new TemplateConfiguration()
def engine = new MarkupTemplateEngine(config)
def tmpl = engine.createTemplate(tpl)
System.out << tmpl.make(model)

You have useful methods available to your templates, like for including other templates:

// include another template
include template: 'foo.tpl'

// include raw content
include unescaped: 'raw.txt'

// escape & include
include escaped: 'to_escape.txt'

And if you want to have your model be type checked, you can either define the model types inside the template like so:

modelTypes = {
    List<Car> cars
}

Or by using the dedicated template creation method:

def modelTypes = [cars: "List<Car>"]

def tmpl = engine.createTypeCheckedModelTemplate(tpl, modelTypes)

Note that this template engine is super fast as it’s statically compiled.

JUnit 4 GroovyAssert class

The venerable GroovyTestCase (JUnit 3 based approach) has often been used as a base class for your test classes — unless you’ve been using the Spock testing framework, of course. One of the drawback of this class is that your test classes can’t extend your own classes, but must derive from GroovyTestCase to benefit from the additional assertion methods.

In earlier versions of Groovy we introduced the JUnit 4-friendly GroovyAssert, which is a convenient class offering the usual assertion methods of GroovyTestCase, but in the form of static methods that you can static import in your test class. In Groovy 2.3, we’ve enriched GroovyAssert with additional features. With these additions, there should be no functionality which is restricted to just JUnit 3, so feel free to move to later versions if you haven’t already done so. We didn’t include all the myriad of assertEquals methods from GroovyTestCase as they are typically less useful than Groovy’s built-in power assert, but it provides some handy shouldFail() and assertScript() methods (GROOVY-6588).

For instance, if you want to leverage the shouldFail(String) and assertScript(String) methods, you can do so as follows:

import static groovy.test.GroovyAssert.shouldFail


import org.junit.Test

class AssertTest {
    @Test void checkBadAddition() {
        shouldFail '''
            groovy.test.GroovyAssert.assertScript 'assert 1 + 1 == 3'
        '''
    }
}

ConfigSlurper

ConfigSlurper has previously supported a single "environments" non-configurational conditional block, but you couldn’t define your own. With Groovy 2.3 you can also create your own such blocks. For instance if you wanted to support "flavors" like OS variants (GROOVY-6383).

Concretely, instead of the familiar environments / production blocks in Grails, let’s register a flavors / prod pair: 

def conf = '''
    a.b.c = 1
    flavors {
        prod {
            a.b.c = 2
        }
    }
'''

def slurper = new ConfigSlurper('prod')
slurper.registerConditionalBlock('flavors', 'prod')

def config = slurper.parse(conf)

assert config.a.b.c == 2

In addition, the isSet() / hasSet() combo methods (GROOVY-4639) have been added so you can double-check if a given node of your configuration has been defined. Before, whether the node wasn’t defined or containing null, you couldn’t differentiate either case easily.

Tools enhancements

Groovysh

Along with a slightly reduced startup time, Groovysh has seen new improvements in its code-completion capabilities:

Commands are now prefixed with ``:'' (link:https://issues.apache.org/jira/browse/GROOVY-6397).

GroovyConsole

It is now possible to configure the font used by the console (GROOVY-6303, although without a UI dialog yet), and also to be able to run a selected snippet of code reusing the imports defined in your script making it easier to just run quick snippets of your script. The ability to comment or uncomment selected code by pressing Ctrl + was added with GROOVY-6459.

Documentation

New documentation

We are still working on the brand new documentation for Groovy (in Asciidoc(tor) format), so you can already have a glimpse at what’s already covered or not.

We’re looking forward to your help for fleshing out the various TBD ("To Be Done") sections of the documentation, as it’s a gigantic task to re-document each and every aspect of the language and its libraries! So please shout if you want to contribute to the new documentation! All help is warmly welcome!

Refreshed GroovyDoc documentation style

GroovyDoc has been updated with a new fresh and modern skin that will be part of the future visual identity of the Groovy website. Those style updates are also available by default for your own usage of GroovyDoc, making your own documentation nicer on the eye.

You can have a look at the GroovyDoc documentation for Groovy 2.3.0.

Refreshed Groovy GDK documentation style

We also took the opportunity to apply the same stylesheet to our DocGenerator tool which is responsible for the generation of the GDK documentation, showing the methods the Groovy library adds on top of the JDK classes.

Please also have a look at the new restyled GDK documentation.

Dependency upgrades

The following dependencies have been upgraded:

  • GPars 1.2 for all your concurrency, asynchronous or parallelism needs:

    • improvements in the dataflow area, such as lazy tasks and easy fork-and-join on Promises

    • actors and dataflow operators now use the Groovy @DelegatesTo annotation to allow for statically compiled bodies

    • GPars timers and thread-locals have been made more friendly towards managed environments and the GParsConfig class now allows GPars to be completely shutdown

  • Gradle 1.10 for building Groovy

  • ASM 5.0.1 library for generating our bytecode (also needed for our JDK 8 support)

  • JLine 2.11 and JANSI 1.11 library for Groovysh

  • Ant 1.9.3 for the Ant builder

  • TestNG 6.8.8 for the TestNG module

Breaking changes

Groovy 2.3.0 introduces a limited list of breaking changes.

First of all,Groovy 2.3.0 now requires JDK 6 as its minimal JDK requirement. Some parts of Groovy 2.3.0 might still run under JDK 5 but no testing has been done on that platform and some parts are known not to work. We encourage everyone to move to at least JDK 6.

In Groovy 2.3.0, we reworked our implementation of generics handling. Although we don’t know of any particular breakage so far, the static type checker might report new errors as it can be stricter than before. If ever you encounter such new errors in this area, please report them as soon as you encounter them.

With the introduction of "traits" in Groovy 2.3, the trait keyword is an addition to the list of keyword of the languages, with the consequence that variables or fields that would use trait as name with yield a compilation error. So you would have to change the name of your variable and recompile your code.

A few updates have been made to the XML support around whitespace handling, and text node handling:

With the new default methods on interfaces in JDK 8, there was particularly one, a List#sort(Comparable) method, which conflicted with one of the GDK, so we had to remove ours to stay compliant with JDK 8.

We fixed a race condition in AbstractHttpServlet#applyResourceNameMatcher which incurred a small change in behavior. This feature is seldomly used and doesn’t seem to have impacted users of the Groovy servlet machinery so far.

You can look at the list of the breaking changes from our JIRA issue tracker.