Hi all,

The Groovy development team is pleased to announce the release of the first
beta of Groovy 2.2, along with a bug fix release of Groovy 2.1.6.

Both Groovy 2.1.6 and 2.2.0-beta-1 contain fixes for the recently
discovered JavaDoc vulnerability<http://www.us-cert.gov/ncas/alerts/TA13-169A>,
that also affected GroovyDoc.

Let me highlight a few interesting points in this 2.2 beta.
Implicit closure coercion

Java 8 will feature lambdas, which are similar to Groovy’s closures. One
particular aspect which is interesting with lambdas is how they are
converted transparently by Java to interface types that contain one single
abstract method. With Groovy closures, except for a few cases, we have to
explicitly use the as operator to do the coercion. In Groovy 2.2, we are
allowing the same transparent closure
coercion<http://docs.codehaus.org/display/GroovyJSR/GEP+12+-+SAM+coercion>to
happen, but without the explicit as type coercion, and furthermore, we
make it possible to work as well with abstract classes as well.

interface Predicate {

   boolean test(obj)

}

List filter(List list, Predicate pred) {

   list.findAll { pred.test(it) }

}

def input = [1, 2, 3, 4, 5]

def odd = filter(input) { it % 2 == 1 }

assert odd == [1, 3, 5]

Notice how the closure is coerced into a Predicate instance. Without that
new capabilities, we would have had to write the following instead:

def odd = filter(input, { it % 2 == 1} as Predicate)

That way, Groovy closure coercion to SAM types is as concise as Java 8
lambda closure convertion.
@Memoized AST transformation for methods

Similarly to our Closure memoization capability, you can now annotate your
methods with the new @Memoized
annotation<http://jira.codehaus.org/browse/GROOVY-4993>.
It will use the same underlying cache solution used for closures, and will
cache the result of previous executions of the annotated method with the
same entry parameters.

import groovy.transform.Memoized

@Memoized int expensiveOp(int a, int b) {

   sleep 1000

   return a + b

}

// one second to return

expensiveOp(1, 2)

// immediate result returned

expensiveOp(1, 2)
New DelegatingScript base class for scripts

With the CompilerConfiguration class that you pass to GroovyShell (as well
as GroovyClassLoader and others), you can define a base script class for
the scripts that will be compiled with that shell. It’s handy to share
common methods to all scripts.

For DSL purposes, it’s interesting to actually delegate the method calls
and unbound variable assignments to a different object than the script
itself, thanks to the new
DelegatingScript<http://jira.codehaus.org/browse/GROOVY-6076>
.

To make it more concrete, let’s have a look at the following configuration
script:

// import the CompilerConfiguration class

// to configure the base script class

import org.codehaus.groovy.control.CompilerConfiguration

// the script we want to compile

def scriptContent = '''

   name = "Guillaume"

   sayHi()

'''

// the class definition of the delegate

class Person {

   String name

   void sayHi() {

       println "Hi $name"

   }

}

// configure the base script class

def cc = new CompilerConfiguration()

cc.scriptBaseClass = DelegatingScript.class.name

// parse script with GroovyShell

// and the configuration

def sh = new GroovyShell(cc)

def script = sh.parse(scriptContent)

// set the delegate and run the script

def p = new Person()

script.setDelegate(p)

script.run()

// the name is set correctly

// and the output will display "Hi Guillaume"

assert p.name == "Guillaume"
@DelegatesTo with generics type tokens

The @DelegatesTo annotation, introduced in Groovy 2.1 that helps the type
checker, IDEs, tools, to provide better support for DSLs using closure
delegation strategies, works with generics token
types<http://jira.codehaus.org/browse/GROOVY-6134>as well. You can
tell Groovy that the delegatee is of the type of the
generics component:

import groovy.transform.*

@InheritConstructors

class MyList extends LinkedList<String> {}

public <T> Object map(

     @DelegatesTo.Target List<T> target,

     @DelegatesTo(genericTypeIndex = 0) Closure arg) {

   arg.delegate = target.join('')

   arg()

}

@TypeChecked

def test() {

   map(new MyList(['f', 'o', 'o'])) {

       assert toUpperCase() == 'FOO'

   }

}

Note the genericTypeIndex attribute of @DelegatesTo that points at the
index of the generic component. Unfortunately, as the generic placeholders
are not kept at the bytecode level, it’s impossible to just reference T,
and we had to use an index to point at the right type.
Precompiled type checking extensions

The static type checking extensions introduced in Groovy 2.1 were working
solely with non-compiled scripts. But with this beta, you can also specify
a fully-qualified name of the precompiled class implementing your
extension<http://jira.codehaus.org/browse/GROOVY-6043>
:

@TypeChecked(extensions = 'com.enterprise.MyDslExtension')

Type checking extensions now also support two more events:
ambiguousMethods<http://jira.codehaus.org/browse/GROOVY-6039>and
incompatibleReturnType <http://jira.codehaus.org/browse/GROOVY-6044>.
Groovysh enhancements

Groovysh has been expanded with various enhancements:

   -

   support for code completion
<http://jira.codehaus.org/browse/GROOVY-6073>in various places, like
imports, package names, class names, variable
   names, parameter names, keywords, etc.
   -

   a doc command <http://jira.codehaus.org/browse/GROOVY-6150> allows you
   to open the relevant JavaDoc and Groovy GDK web pages to have more
   information for a given class, for example try in Groovysh:
   doc java.util.List
   -

   you can complete file names
<http://jira.codehaus.org/browse/GROOVY-6145>inside strings,
particularly handy for your scripting tasks where you want
   to open a file with new File("data.|”) (where the pipe character is the
   position of your cursor), and then hit the TAB key to have the completion
   of the file name

OSGi manifests for the “invoke dynamic” JARs

If you’re using Groovy in the context of an OSGi container, the Groovy JARs
contained the right OSGi metadata information in its manifest. However, it
wasn’t the case for the “invoke dynamic” JARs, as the underlying library
used by the Gradle OSGi plugin wasn’t supporting JDK 7 bytecode.
Fortunately, this deficiency has been fixed, the Gradle OSGi plugin
updated, and we’re now able to have our “indy” JARs work fine under OSGi
has well.

Those changes have not yet been backported to the Groovy 2.1.x branch, but
will likely be. We’re looking forward to hearing your feedback, for those
using Groovy and OSGi.

For more details about the various bug fixed in those releases, please have
a look at the JIRA release notes:

   -

   Groovy 
2.2-beta-1<http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&version=19074>
   -

   Groovy 
2.1.6<http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&version=19335>


And then, go download Groovy 2.2-beta-1 and Groovy 2.1.6 on our Download
area <http://groovy.codehaus.org/Download?nc> while it’s hot!

Thanks a lot for all your contributions, and we’re looking forward to your
feedback on those releases.


-- 
Guillaume Laforge
Groovy Project Manager
Pivotal, Inc.

Blog: http://glaforge.appspot.com/
Social: @glaforge <http://twitter.com/glaforge> /
Google+<https://plus.google.com/u/0/114130972232398734985/posts>

Reply via email to