blob: 0cbf311864d33c407768ca627bb6aa2a00dd54d2 [file] [log] [blame]
The newly released Groovy 2.0 brings key static features to the language
with static type checking and static compilation, adopts JDK 7 related
improvements with Project Coin syntax enhancements and the support of
the new `invokedynamic` JVM instruction, and becomes more modular
than before. In this article, were going to look into those new
features in more detail.
[[Groovy20releasenotes-Astaticthemeforadynamiclanguage]]
== A static theme for a dynamic language
[[Groovy20releasenotes-Statictypechecking]]
=== Static type checking
Groovy, by nature, is and will always be a dynamic language. However,
Groovy is often used as a "Java scripting language", or as a "better
Java" (ie. a Java with less boilerplate and more power features). A lot
of Java developers actually use and embed Groovy in their Java
applications as an extension language, to author more expressive
business rules, to further customize the application for different
customers, etc. For such Java-oriented use cases, developers dont need
all the dynamic capabilities offered by the language, and they usually
expect the same kind of feedback from the Groovy compiler as the one
given by javac. In particular, they want to get compilation errors
(rather than runtime errors) for things like typos on variable or method
names, incorrect type assignments and the like. Thats why Groovy 2
features static type checking support.** +
**
[[Groovy20releasenotes-Spottingobvioustypos]]
==== Spotting obvious typos
The static type checker is built using Groovys existing powerful AST
(Abstract Syntax Tree) transformation mechanisms but for those not
familiar with these mechanisms you can think of it as an optional
compiler plugin triggered through an annotation. Being an optional
feature, you are not forced to use it if you dont need it. To trigger
static type checking, just use the @TypeChecked annotation on a method
or on a class to turn on checking at your desired level of granularity.
Lets see that in action with a first example:
[source,groovy]
-------------------------------------------------
import groovy.transform.TypeChecked
void someMethod() {}
@TypeChecked
void test() {
// compilation error:
// cannot find matching method sommeeMethod()
sommeeMethod()
def name = "Marion"
// compilation error:
// the variable naaammme is undeclared
println naaammme
}
-------------------------------------------------
We annotated the test() method with the @TypeChecked annotation, which
instructs the Groovy compiler to run the static type checking for that
particular method at compilation time. Were trying to call someMethod()
with some obvious typos, and to print the name variable again with
another typo, and the compiler will throw two compilation errors because
respectively, the method and variable are not found or declared.** +
**
[[Groovy20releasenotes-Checkyourassignmentsandreturnvalues]]
==== Check your assignments and return values
The static type checker also verifies that the return types and values
of your assignments are coherent:
[source,groovy]
-----------------------------------------
import groovy.transform.TypeChecked
@TypeChecked
Date test() {
// compilation error:
// cannot assign value of Date
// to variable of type int
int object = new Date()
String[] letters = ['a', 'b', 'c']
// compilation error:
// cannot assign value of type String
// to variable of type Date
Date aDateVariable = letters[0]
// compilation error:
// cannot return value of type String
// on method returning type Date
return "today"
}
-----------------------------------------
In this example, the compiler will complain about the fact you cannot
assign a Date in an int variable, nor can you return a String instead of
a Date value specified in the method signature. The compilation error
from the middle of the script is also interesting, as not only does it
complain of the wrong assignment, but also because it shows type
inference at play, because the type checker, of course, knows that
letters[0] is of type String, because were dealing with an array of
Strings.** +
**
[[Groovy20releasenotes-Moreontypeinference]]
==== More on type inference
Since were mentioning type inference, lets have a look at some other
occurrences of it. We mentioned the type checker tracks the return types
and values:
[source,groovy]
--------------------------------------------
import groovy.transform.TypeChecked
@TypeChecked
int method() {
if (true) {
// compilation error:
// cannot return value of type String
// on method returning type int
'String'
} else {
42
}
--------------------------------------------
Given a method returning  a value of primitive type int, the type
checker is able to also check the values returned from different
constructs like if / else branches, try / catch blocks or switch / case
blocks. Here, in our example, one branch of the if / else blocks tries
to return a String value instead of a primitive int, and the compiler
complains about it.** +
**
[[Groovy20releasenotes-Commontypeconversionsstillallowed]]
==== Common type conversions still allowed
The static type checker, however, wont complain for certain automatic
type conversions that Groovy supports. For instance, for method
signatures returning String, boolean or Class, Groovy converts return
values to these types automatically:
[source,groovy]
----------------------------------------------------------
import groovy.transform.TypeChecked
@TypeChecked
boolean booleanMethod() {
"non empty strings are evaluated to true"
}
assert booleanMethod() == true
@TypeChecked
String stringMethod() {
// StringBuilder converted to String calling toString()
new StringBuilder() << "non empty string"
}
assert stringMethod() instanceof String
@TypeChecked
Class classMethod() {
// the java.util.List class will be returned
"java.util.List"
}
assert classMethod() == List 
----------------------------------------------------------
The static type checker is also clever enough to do type inference:
[source,groovy]
------------------------------------------------
import groovy.transform.TypeChecked
@TypeChecked
void method() {
def name = " Guillaume "
// String type inferred (even inside GString)
println "NAME = ${name.toUpperCase()}"
// Groovy GDK method support
// (GDK operator overloading too)
println name.trim()
int[] numbers = [1, 2, 3]
// Element n is an int
for (int n in numbers) {
println n
}
}
------------------------------------------------
Although the name variable was defined with def, the type checker
understands it is of type String. Then, when this variable is used in
the interpolated string, it knows it can call Strings toUpperCase()
method, or the trim() method later one, which is a method added by the
Groovy Development Kit decorating the String class. Last, when iterating
over the elements of an array of primitive ints, it also understands
that an element of that array is obviously an int.** +
**
[[Groovy20releasenotes-Mixingdynamicfeaturesandstaticallytypedmethods]]
==== Mixing dynamic features and statically typed methods
An important aspect to have in mind is that using the static type
checking facility restricts what you are allowed to use in Groovy. Most
runtime dynamic features are not allowed, as they cant be statically
type checked at compilation time. So adding a new method at runtime
through the types metaclasses is not allowed. But when you need to use
some particular dynamic feature, like Groovys builders, you can opt out
of static type checking should you wish to. +
  +
The @TypeChecked annotation can be put at the class level or at the
method level. So if you want to have a whole class type checked, put the
annotation on the class, and if you want only a few methods type
checked, put the annotation on just those methods. Also, if you want to
have everything type checked, except a specific method, you can annotate
the latter with @TypeChecked(TypeCheckingMode.SKIP) or
@TypeChecked(SKIP) for short, if you statically import the associated
enum. Lets illustrate the situation with the following script, where
the greeting() method is type checked, whereas the generateMarkup()
method is not:
[source,groovy]
-----------------------------------------------------------
import groovy.transform.TypeChecked
import groovy.xml.MarkupBuilder
// this method and its code are type checked
@TypeChecked
String greeting(String name) {
generateMarkup(name.toUpperCase())
}
// this method isn't type checked
// and you can use dynamic features like the markup builder
String generateMarkup(String name) {
def sw = new StringWriter()
new MarkupBuilder(sw).html {
body {
div name
}
}
sw.toString()
}
assert greeting("Cédric").contains("CÉDRIC")
-----------------------------------------------------------
[[Groovy20releasenotes-Typeinferenceandinstanceofchecks]]
==== Type inference and instanceof checks
Current production releases of Java dont support general type
inference; hence we find today many places where code is often quite
verbose and cluttered with boilerplate constructs. This obscures the
intent of the code and without the support of powerful IDEs is also
harder to write. This is the case with instanceof checks: You often
check the class of a value with instanceof inside an if condition, and
afterwards in the if block, you must still use casts to be able to use
methods of the value at hand. In plain Groovy, as well as in the new
static type checking mode, you can completely get rid of those casts.
[source,groovy]
-----------------------------------------------------
import groovy.transform.TypeChecked
import groovy.xml.MarkupBuilder
@TypeChecked
String test(Object val) {
if (val instanceof String) {
// unlike Java:
// return ((String)val).toUpperCase()
val.toUpperCase()
} else if (val instanceof Number) {
// unlike Java:
// return ((Number)val).intValue().multiply(2)
val.intValue() * 2
}
}
assert test('abc') == 'ABC'
assert test(123) == '246'
-----------------------------------------------------
In the above example, the static type checker knows that the val
parameter is of type String inside the if block, and of type Number in
the else if block, without requiring any cast.** +
**
[[Groovy20releasenotes-LowestUpperBound]]
==== Lowest Upper Bound
The static type checker goes a bit further in terms of type inference in
the sense that it has a more granular understanding of the type of your
objects. Consider the following code:
[source,groovy]
----------------------------------------------------------
import groovy.transform.TypeChecked
// inferred return type:
// a list of numbers which are comparable and serializable
@TypeChecked test() {
// an integer and a BigDecimal
return [1234, 3.14]
----------------------------------------------------------
In this example, we return, intuitively, a list of numbers: an Integer
and a BigDecimal. But the static type checker computes what we call a
"lowest upper bound", which is actually a list of numbers which are
also serializable and comparable. Its not possible to denote that type
with the standard Java type notation, but if we had some kind of
intersection operator like an ampersand, it could look like List<Number
& Serializable & Comparable>.** +
**
[[Groovy20releasenotes-Flowtyping]]
==== Flow typing
Although this is not really recommended as a good practice, sometimes
developers use the same untyped variable to store values of different
types. Look at this method body:
[source,groovy]
-----------------------------------------------------------
import groovy.transform.TypeChecked
@TypeChecked test() {
def var = 123 // inferred type is int
var = "123" // assign var with a String
println var.toInteger() // no problem, no need to cast
var = 123
println var.toUpperCase() // error, var is int!
-----------------------------------------------------------
The var variable is initialized with an int. Then, a String is assigned.
The "flow typing" algorithm follows the flow of assignment and
understands that the variable now holds a String, so the static type
checker will be happy with the toInteger() method added by Groovy on top
of String. Next, a number is put back in the var variable, but then,
when calling toUpperCase(), the type checker will throw a compilation
error, as theres no toUpperCase() method on Integer. +
  +
There are some special cases for the flow typing algorithm when a
variable is shared with a closure which are interesting. What happens
when a local variable is referenced in a closure inside a method where
that variable is defined? Lets have a look at this example:
[source,groovy]
-------------------------------------------------------
import groovy.transform.TypeChecked
@TypeChecked test() {
def var = "abc"
def cl = {
if (new Random().nextBoolean()) var = new Date()
}
cl()
var.toUpperCase() // compilation error!
-------------------------------------------------------
The var local variable is assigned a String, but then, var might be
assigned a Date if some random value is true. Typically, its only at
runtime that we really know if the condition in the if statement of the
closure is made or not. Hence, at compile-time, theres no chance the
compiler can know if var now contains a String or a Date. Thats why the
compiler will actually complain about the toUpperCase() call, as it is
not able to infer that the variable contains a String or not. This
example is certainly a bit contrived, but there are some more
interesting cases:
[source,groovy]
--------------------------------------------
import groovy.transform.TypeChecked
class A { void foo() {} }
class B extends A { void bar() {} }
@TypeChecked test() {
def var = new A()
def cl = { var = new B() }
cl()
// var is at least an instance of A
// so we are allowed to call method foo()
var.foo()
--------------------------------------------
In the test() method above, var is assigned an instance of A, and then
an instance of B in the closure which is call afterwards, so we can at
least infer that var is of type A. +
  +
All those checks added to the Groovy compiler are done at compile-time,
but the generated bytecode is still the same dynamic code as usual no
changes in behavior at all. +
  +
Since the compiler now knows a lot more about your program in terms of
types, it opens up some interesting possibilities: what about compiling
that type checked code statically? The obvious advantage will be that
the generated bytecode will more closely resemble the bytecode created
by the javac compiler itself, making statically compiled Groovy code as
fast as plain Java, among other advantages. In the next section, well
learn more about Groovys static compilation.** +
**
[[Groovy20releasenotes-Staticcompilation]]
=== Static compilation
As we shall see in the following chapter about the JDK 7 alignments,
Groovy 2.0 supports the new `invokedynamic` instruction of the JVM
and its related APIs, facilitating the development of dynamic languages
on the Java platform and bringing some additional performance to
Groovys dynamic calls. However, unfortunately shall I say, JDK 7 is not
widely deployed in production at the time of this writing, so not
everybody has the chance to run on the latest version. So developers
looking for performance improvements would not see much changes in
Groovy 2.0, if they arent able to run on JDK 7. Luckily, the Groovy
development team thought those developers could get interesting
performance boost, among other advantages, by allowing type checked code
to be compiled statically. +
  +
Without further ado, lets dive in and use the new @CompileStatic
transform:
[source,groovy]
-------------------------------------
import groovy.transform.CompileStatic
@CompileStatic
int squarePlusOne(int num) {
num * num + 1
}
assert squarePlusOne(3) == 10 
-------------------------------------
This time, instead of using @TypeChecked, use @CompileStatic, and your
code will be statically compiled, and the bytecode generated here will
look like javacs bytecode, running just as fast. Like the @TypeChecked
annotation, @CompileStatic can annotate classes and methods, and
@CompileStatic(SKIP) can bypass static compilation for a specific
method, when its class is marked with @CompileStatic. +
  +
Another advantage of the javac-like bytecode generation is that the size
of the bytecode for those annotated methods will be smaller than the
usual bytecode generated by Groovy for dynamic methods, since to support
Groovys dynamic features, the bytecode in the dynamic case contains
additional instructions to call into Groovys runtime system. +
  +
Last but not least, static compilation can be used by framework or
library code writers to help avoid adverse interactions when dynamic
metaprogramming is in use in several parts of the codebase. The dynamic
features available in languages like Groovy are what give developers
incredible power and flexibility but if care is not taken, different
assumptions can exist in different parts of the system with regards to
what metaprogramming features are in play and this can have unintended
consequences. As a slightly contrived example, consider what happens if
you are using two different libraries, both of which add a similarly
named but differently implemented method to one of your core classes.
What behaviour is expected? Experienced users of dynamic languages will
have seen this problem before and probably heard it referred to as
"monkey patching". Being able to statically compile parts of your code
base those parts that dont need dynamic features shields you from
the effects of monkey patching, as the statically compiled code doesnt
go through Groovys dynamic runtime system. Although dynamic runtime
aspects of the language are not allowed in a static compilation context,
all the usual AST transformation mechanisms work just as well as before,
since most AST transforms perform their magic at compilation time. +
  +
In terms of performance, Groovys statically compiled code is usually
more or less as fast as javacs. In the few micro-benchmarks the
development team used, performance is identical in several cases, and
sometimes its slightly slower. +
  +
Historically, thanks to the transparent and seamless integration of Java
and Groovy, we used to advise developers to optimize some hotspot
routines in Java for further performance gains, but now, with this
static compilation option, this is no longer the case, and people
wishing to develop their projects in full Groovy can do so.** +
**
[[Groovy20releasenotes-TheJava7andJDK7theme]]
== The Java 7 and JDK 7 theme
The grammar of the Groovy programming language actually derives from the
Java grammar itself, but obviously, Groovy provides additional nice
shortcuts to make developers more productive. This familiarity of syntax
for Java developers has always been a key selling point for the project
and its wide adoption, thanks to a flat learning curve. And of course,
we expect Groovy users and newcomers to also want to benefit from the
few syntax refinements offered by Java 7 with its "Project Coin"
additions. +
  +
Beyond the syntax aspects, JDK 7 also brings interesting novelties to
its APIs, and for a first time in a long time, even a new bytecode
instruction called `invoke dynamic`, which is geared towards helping
implementors develop their dynamic languages more easily and benefit
from more performance.** +
**
[[Groovy20releasenotes-ProjectCoinsyntaxenhancements]]
=== Project Coin syntax enhancements
Since day 1 (that was back in 2003 already!) Groovy has had several
syntax enhancements and features on top of Java. One can think of
closures, for example, but also the ability to put more than just
discrete values in switch / case statements, where Java 7 only allows
Strings in addition. So some of the Project Coin syntax enhancements,
like Strings in switch, were already present in Groovy. However, some of
the enhancements are new, such as binary literals, underscore in number
literals, or the multi catch block, and Groovy 2 supports them. The sole
omission from the Project Coin enhancements is the "try with
resources" construct, for which Groovy already provides various
alternatives through the rich API of the Groovy Development Kit.
[[Groovy20releasenotes-Binaryliterals]]
==== Binary literals
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:
[source,groovy]
------------------------------
int x = 0b10101111
assert x == 175
byte aByte = 0b00100001
assert aByte == 33
int anInt = 0b1010000101000101
assert anInt == 41285
------------------------------
[[Groovy20releasenotes-Underscoreinnumberliterals]]
==== Underscore in number literals
When writing long literal numbers, its 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, its easier to spot those groups:
[source,groovy]
--------------------------------------------------
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
--------------------------------------------------
[[Groovy20releasenotes-Multicatchblock]]
==== Multicatch block
When catching exceptions, we often replicate the catch block for two or
more exceptions as we want to handle them in the same way. A workaround
is either to factor out the commonalities in its own method, or in a
more ugly fashion to have a catch-all approach by catching Exception, or
worse, Throwable. With the multi catch block, were able to define
several exceptions to be catch and treated by the same catch block:
[source,groovy]
-----------------------------------------------
try {
/* ... */
} catch(IOException | NullPointerException e) {
/* one block to handle 2 exceptions */
}
-----------------------------------------------
[[Groovy20releasenotes-InvokeDynamicsupport]]
=== Invoke Dynamic support
As we mentioned earlier in this article, JDK 7 came with a new bytecode
instruction called `invokedynamic`, as well as with its associated
APIs. Their goal is to help dynamic language implementors in their job
of crafting their languages on top of the Java platform, by simplifying
the wiring of dynamic method calls, by defining "call sites" where
dynamic method call section can be cached, "method handles" as method
pointers, "class values" to store any kind of metadata along class
objects, and a few other things. One caveat though, despite promising
performance improvements, `invokedynamic` hasnt yet fully been
optimized inside the JVM, and doesnt yet always deliver the best
performance possible, but update after update, the optimizations are
coming. +
  +
Groovy brought its own implementation techniques, to speed up method
selection and invocation with "call site caching", to store
metaclasses (the dynamic runtime equivalent of classes) with its
metaclass registry, to perform native primitive calculations as fast as
Java, and much more. But with the advent of `invokedynamic`, we can
rebase the implementation of Groovy on top of these APIs and this JVM
bytecode instruction, to gain performance improvements and to simplify
our code base. +
  +
If youre lucky to run on JDK 7, youll be able to use a new version of
the Groovy JARs which has been compiled with the `invokedynamic`
support. Those JARs are easily recognizable as they use the `-indy`
classifier in their names.**  +
**
[[Groovy20releasenotes-Enablinginvokedynamicsupport]]
==== Enabling invoke dynamic support
Using the `indy` JARs is not enough, however, to compile your Groovy
code so that it leverages the `invokedynamic` support. For that,
youll have to use the indy flag when using the `groovyc` compiler or
the `groovy` command. This also means that even if youre using the
indy JARs, you can still target JDK 5 or 6 for compilation. +
  +
Similarly, if youre using the groovyc Ant task for compiling your
projects, you can also specify the indy attribute:
[source,xml]
-------------------------------------------------------------
...
<taskdef name="groovyc"
classname="org.codehaus.groovy.ant.Groovyc"
classpathref="cp"/>
...
<groovyc srcdir="${srcDir}" destdir="${destDir}" indy="true">
<classpath>
...
</classpath>
</groovyc>
... 
-------------------------------------------------------------
The Groovy Eclipse Maven compiler plugin hasnt yet been updated with
the support of Groovy 2.0 but this will be the case shortly. For GMaven
plugin users, although its possible to configure the plugin to use
Groovy 2.0 already, theres currently no flag to enable the invoke
dynamic support. Again, GMaven will also be updated soon in that
regard. +
  +
When integrating Groovy in your Java applications, with GroovyShell, for
example, you can also enable the invoke dynamic support by passing a
CompilerConfiguration instance to the GroovyShell constructor on which
you access and set the optimization options:
[source,groovy]
-----------------------------------------------------------
CompilerConfiguration config = new CompilerConfiguration();
config.getOptimizationOptions().put("indy", true);
config.getOptimizationOptions().put("int", false);
GroovyShell shell = new GroovyShell(config); 
-----------------------------------------------------------
As invokedynamic is supposed to be a full replacement to dynamic method
dispatch, it is also necessary to disable the primitive optimizations
which generate extra bytecode that is here to optimize edge cases. Even
if it is in some cases slower than with primitive optimizations
activated, future versions of the JVM will feature an improved JIT which
will be capable of inlining most of the calls and remove unnecessary
boxings.
[[Groovy20releasenotes-Promisingperformanceimprovements]]
==== Promising performance improvements
In our testing, we noticed some interesting performance gains in some
areas, whereas other programs could run slower than when not using the
invoke dynamic support. The Groovy team has further performance
improvements in the pipeline for Groovy 2.1 however, but we noticed the
JVM isnt yet finely tuned and still has a long way to go to be fully
optimized. But fortunately, upcoming JDK 7 updates (in particular update
8) should already contain such improvements, so the situation can only
improve. Furthermore, as invoke dynamic is used for the implementation
of JDK 8 Lambdas, we can be sure more improvements are forthcoming.** +
**
[[Groovy20releasenotes-AmoremodularGroovy]]
== A more modular Groovy
Well finish our journey through the new features of Groovy 2.0 by
speaking about modularity. Just like Java, Groovy is not just a
language, but its also a set of APIs serving various purposes:
templating, Swing UI building, Ant scripting, JMX integration, SQL
access, servlet serving, and more. The Groovy deliverables were bundling
all these features and APIs inside a single big JAR. However, not
everybody needs everything at all times in their own applications: you
might be interested in the template engine and the servlets if youre
writing some web application, but you might only need the Swing builder
when working on a rich desktop client program.**  +
**
[[Groovy20releasenotes-Groovymodules]]
=== Groovy modules
So the first goal of the modularity aspect of this release is to
actually split the original Groovy JAR into smaller modules, smaller
JARs. The core Groovy JAR is now twice as small, and we have the
following feature modules available:** +
  +
**
* Ant: for scripting Ant tasks for automating administration tasks
* BSF: for integrating Groovy in your Java applications with the old
Apache Bean Scripting Framework
* Console: module containing the Groovy Swing console
* GroovyDoc: for documenting your Groovy and Java classes
* Groovysh: module corresponding to the Groovysh command-line shell
* JMX: for exposing and consuming JMX beans
* JSON: for producing and consuming JSON payloads
* JSR-223: for integrating Groovy in your Java applications with the JDK
6+ javax.scripting APIs
* Servlet: for writing and serving Groovy script servlets and templates
* SQL: for querying relational databases
* Swing: for building Swing UIs
* Templates: for using the template engine
* Test: for some test support, like the GroovyTestCase, mocking, and
more
* TestNG: for writing TestNG tests in Groovy
* XML: for producing and consuming XML documents
With Groovy 2, youre now able to just pick up the modules youre
interested in, rather than bringing everything on your classpath.
However, we still provide the `all` JAR which contains everything, if
you dont want to complicate your dependencies for just a few megabytes
of saved space. We also provide those JARs compiled with the `invokedynamic`
support as well, for those running on JDK 7.
[[Groovy20releasenotes-Extensionmodules]]
=== Extension modules
The work on making Groovy more modular also yielded an interesting new
feature: extension modules. By splitting Groovy into smaller modules, a
mechanism for modules to contribute extension methods has been created.
That way, extension modules can provide instance and static methods to
other classes, including the ones from the JDK or third-party libraries.
Groovy uses this mechanism to decorate classes from the JDK, to add new
useful methods to classes like String, File, streams, and many more
for example, a getText() method on URL allows you to retrieve the
content of a remote URL through an HTTP get. Notice also that those
extension methods in your modules are also understood by the static type
checker and compiler. But lets now have a look at how you can add new
methods to existing types.** +
**
[[Groovy20releasenotes-Contributinganinstancemethod]]
==== Contributing an instance method
To add new methods to an existing type, youll have to create a helper
class that will contain those methods. Inside that helper class, all the
extension methods will actually be public (the default for Groovy but
required if implementing in Java) and static (although they will be
available on instances of that class). They will always take a first
parameter which is actually the instance on which this method will be
called. And then following parameters will be the parameters passed when
calling the method. This is the same convention use for Groovy
categories. +
  +
Say we want to add a greets() method on String, that would greet the
name of the person passed in parameters, so that you could that method
as follow:
[source,groovy]
-------------------------------------------------------------
assert "Guillaume".greets("Paul") == "Hi Paul, I'm Guillaume"
-------------------------------------------------------------
To accomplish that, you will create a helper class with an extension
method like so:
[source,groovy]
---------------------------------------------------
 
package com.acme
class MyExtension {
static String greets(String self, String name) {
"Hi ${name}, I'm ${self}"
}
}
---------------------------------------------------
[[Groovy20releasenotes-Contributingastaticmethod]]
==== Contributing a static method
Static extension methods are defined using the same mechanism, but have
to be declared in a separate class. The extension module descriptor then
determines whether the class provides instance or static methods. Lets
add a new static method to Random to get a random integer between two
values, you could proceed as in this class:
[source,groovy]
---------------------------------------------------------------
package com.acme
class MyStaticExtension {
static String between(Random selfType, int start, int end) {
new Random().nextInt(end - start + 1) + start
}
---------------------------------------------------------------
That way, you are able to use that extension method as follows:
[source,groovy]
--------------------
Random.between(3, 4)
--------------------
[[Groovy20releasenotes-Extensionmoduledescriptor]]
==== Extension module descriptor
Once youve coded your helper classes (in Groovy or even in Java)
containing the extension methods, you need to create a descriptor for
your module. You must create a file called
org.codehaus.groovy.runtime.ExtensionModule in the META-INF/services
directory of your module archive. Four essential fields can be defined,
to tell the Groovy runtime about the name and version of your module, as
well as to point at your helper classes for extension methods with a
comma-separated list of class names. Here is what our final module
descriptor looks like:
---------------------------------------------------
moduleName = MyExtension
moduleVersion = 1.0
extensionClasses = com.acme.MyExtension
staticExtensionClasses = com.acme.MyStaticExtension
---------------------------------------------------
With this extension module descriptor on the classpath, you are now able
to use those extension methods in your code, without needing an import
or anything else, as those extension methods are automatically
registered.** +
**
[[Groovy20releasenotes-Grabbinganextension]]
==== Grabbing an extension
With the @Grab annotation in your scripts, you can fetch dependencies
from Maven repositories like Maven Central. With the addition of the
@GrabResolver annotation, you can specify your own location for your
dependencies as well. If you are "grabbing" an extension module
dependency through this mechanism, the extension method will also be
installed automatically. Ideally, for consistency, your module name and
version should be coherent with the artifact id and version of your
artifact.** +
**
[[Groovy20releasenotes-Summary]]
== Summary
Groovy is very popular among Java developers and offers them a mature
platform and ecosystem for their application needs. But without resting
still, the Groovy development team continues to further improve the
language and its APIs to help its users increase their productivity on
the Java platform. +
  +
Groovy 2.0 responds to three key themes:** +
**
* More performance: with the support of JDK 7 Invoke Dynamic to speed up
Groovy for those lucky to have JDK 7 already in production, but also
with static compilation for JDK 5 and beyond for everyone, and
particularly those ready to abandon some aspects of dynamicity to shield
themselves from the reach of "monkey patching" and to gain the same
speed as Java.
* More Java friendliness: with the support of the Java 7 Project Coin
enhancements to keep Groovy and Java as close syntax cousins as ever,
and with the static type checker to have the same level of  feedback and
type safety as provided by the javac compiler for developers using
Groovy as a Java scripting language
* More modularity: with a new level of modularity, Groovy opens the
doors for smaller deliverables, for example for integration in mobile
applications on Android, and allowing the Groovy APIs to grow and evolve
with newer versions and newer extension modules, as well as allowing
users to contribute extension methods to existing types.