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:
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.
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.
Then we create a class, Bird, that implements that trait, and instantiate it:
We can check that the Bird instance does have the new fly() method mixed-in:
Groovy traits are stateful (unlike Java 8 interface default methods).
A trait can have Groovy properties like plain classes:
This time, the Bird class implements that Named trait:
We can instantiate the Bird with the named-argument constructor shortcut provided by Groovy:
We assert that the instantiated Bird does have the name property added to it:
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:
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:
Traits are compatible with static type checking and compilation, as well as our usual dynamic behavior. Trait mixed-in methods are actually “real” methods (ie. 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):
You can find more information on traits in the exhaustive trait documentation.
New and updated AST transformations
@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:
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:
You can have a look at the @Builder documentation for the other builder variants.
@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:
Additionally, you can define included / excluded fields, access individual field comparators with methods like comparatorByFirst().
More details on the @Sortable documentation page.
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:
The src variable will contain the following data URI:
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:
As I mentioned above, you can also write @SourceURI URI src, if you want to have a URI instead of a String.
@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:
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():
We can then have the script below transparently implement the internalRun() method instead of the usual run() one:
New NIO module for Java 7+
You’ll find familiar methods of the Groovy GDK on File also available on Path like these ones:
Various minor performance improvements across the board, for static compilation, the “invoke dynamic” 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 seralization, 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:
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:
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:
And have the following model:
You would generate the following XML (or HTML) output:
By doing the following:
You have useful methods available to your templates, like for including other templates:
And if you want to have your model be type checked, you can either define the model types inside the template like so:
Or by using the dedicated template creation method:
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. There should be no reason to move on from JUnit 3 if you haven’t already done so. We didn’t include all of 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
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:
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.
Along with some slightly reduced startup time, Groovysh has seen new improvements in its code-completion capabilities:
line comment command (GROOVY-6459)
completion for keywords (GROOVY-6399)
completion for properties (GROOVY-6395)
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.
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.
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
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 AbstractHttpServler#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.