You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2017/04/25 23:06:04 UTC

[04/20] groovy-user-site git commit: move content to asf-site branch

http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/de805f31/site/src/site/releasenotes/groovy-1.8.adoc
----------------------------------------------------------------------
diff --git a/site/src/site/releasenotes/groovy-1.8.adoc b/site/src/site/releasenotes/groovy-1.8.adoc
deleted file mode 100644
index 25f96d6..0000000
--- a/site/src/site/releasenotes/groovy-1.8.adoc
+++ /dev/null
@@ -1,1554 +0,0 @@
-The 1.8 release of Groovy comes with many new features that greatly
-enhance
-
-* the dynamic expressiveness of Groovy, specifically for defining DSLs
-* runtime performance
-* concurrent and parallel execution
-* design by contract
-* functional programming style
-* first-class JSON support
-* compile-time meta programming
-* and more helpers and library additions
-
-These features have undergone the Groovy developer process with formal
-descriptions, discussion, and voting (GEP - Groovy Enhancement Proposal)
-for core parts and less formal developer discussions and JIRA voting for
-additional parts.
-
-Our goal has stayed the same, though: to give the Java developer a tool
-that makes him more productive, allows him to achieve his goals faster
-and with a smaller margin of error, and extend the scalability of the
-Java platform from full-blown enterprise projects to everyday "getting
-things done" tasks.
-
-[[Groovy18releasenotes-CommandchainsfornicerDomain-SpecificLanguages]]
-== Command chains for nicer Domain-Specific Languages
-
-Thanks to its flexible syntax and its compile-time and runtime
-metaprogramming capabilities, Groovy is well known for its
-Domain-Specific Language capabilities. However, we felt that we could
-improve upon the syntax further by removing additional punctuation
-symbols when users chain method calls. This allows DSL implementors to
-develop command descriptions that read almost like natural sentences.
-
-Before Groovy 1.8, we could omit parentheses around the arguments of a
-method call for top-level statements. But we couldn\u2019t chain method
-calls. The new `command chain` feature allows us to chain such
-parentheses-free method calls, requiring neither parentheses around
-arguments, nor dots between the chained calls. The general idea is that
-a call like `a b c d` will actually be equivalent to `a(b).c(d)`. This
-also works with multiple arguments, closure arguments, and even named
-arguments. Furthermore, such command chains can also appear on the
-right-hand side of assignments. Let\u2019s have a look at some examples
-supported by this new syntax:
-
-[source,groovy]
----------------------------------------------------------------------------------------------------------------
-turn left then right                           // equivalent to: turn(left).then(right)
-take 2.pills of chloroquinine after 6.hours    // equivalent to: take(2.pills).of(chloroquinine).after(6.hours)
-paint wall with red, green and yellow          // equivalent to: paint(wall).with(red, green).and(yellow)
-
-// with named parameters too
-check that: margarita tastes good             // equivalent to: check(that: margarita).tastes(good)
-
-// with closures as parameters
-given { } when { } then { }                    // equivalent to: given({}).when({}).then({})
----------------------------------------------------------------------------------------------------------------
-
-It is also possible to use methods in the chain which take no arguments,
-but in that case, the parentheses are needed:
-
-[source,groovy]
--------------------------------------------------------------------------------------------------
-select all unique() from names                 // equivalent to: select(all).unique().from(names)
--------------------------------------------------------------------------------------------------
-
-If your command chain contains an odd number of elements, the chain will
-be composed of method / arguments, and will finish by a final property
-access:
-
-[source,groovy]
--------------------------------------------------------------------------------------
-take 3 cookies                                 // equivalent to: take(3).cookies
-                                               // and also this: take(3).getCookies()
--------------------------------------------------------------------------------------
-
-This new command chain approach opens up interesting possibilities in
-terms of the much wider range of DSLs which can now be written in
-Groovy. This new feature has been developed thanks to the Google Summer
-of Code program, where our student, Lidia, helped us modify the Groovy
-Antlr grammar to extend top-level statements to accept that command
-chain syntax.
-
-The above examples illustrate using a command chain based DSL but not
-how to create one. You will be able to find some
-http://groovyconsole.appspot.com/tag/gep3[further examples] of `command chains`
-on the Groovy Web Console but to illustrate creating such a
-DSL, we will show just a couple of examples - first using maps and
-Closures:
-
-[source,groovy]
-------------------------------------------------------------------------------------------------------
-show = { println it }
-square_root = { Math.sqrt(it) }
-
-def please(action) {
-  [the: { what ->
-    [of: { n -> action(what(n)) }]
-  }]
-}
-
-please show the square_root of 100             // equivalent to: please(show).the(square_root).of(100)
-// ==> 10.0
-------------------------------------------------------------------------------------------------------
-
-Or if you prefer Japanese and a metaprogramming style (see
-http://d.hatena.ne.jp/uehaj/20100919/1284906117[here] for more details):
-
-[source,groovy]
-----------------------------------------------------------
-// Japanese DSL using GEP3 rules
-Object.metaClass.\u3092�=
-Object.metaClass.\u306e�= {�clos�->�clos(delegate)�}
-
-\u307e\u305a = {�it�}
-\u8868\u793a\u3059\u308b = {�println�it�}
-\u5e73\u65b9\u6839 = {�Math.sqrt(it)�}
-
-\u307e\u305a�100�\u306e�\u5e73\u65b9\u6839�\u3092�\u8868\u793a\u3059\u308b  // First, show the square root of 100
-// => 10.0
-----------------------------------------------------------
-
-As a second example, consider how you might write a DSL for simplifying
-one of your existing APIs. Maybe you need to put this code in front of
-customers, business analysts or testers who might be not hard-core Java
-developers. We\u2019ll use the `Splitter` from the Google
-http://code.google.com/p/guava-libraries/[Guava libraries] project as it
-already has a nice Fluent API. Here is how we might use it out of the
-box:
-
-[source,groovy]
-----------------------------------------------------------------------------------------------------------------
-@Grab('com.google.guava:guava:r09')
-import com.google.common.base.*
-def result = Splitter.on(',').trimResults(CharMatcher.is('_' as char)).split("_a ,_b_ ,c__").iterator().toList()
-assert result == ['a ', 'b_ ', 'c']
-----------------------------------------------------------------------------------------------------------------
-
-It reads fairly well for a Java developer but if that is not your target
-audience or you have many such statements to write, it could be
-considered a little verbose. Again, there are many options for writing a
-DSL. We\u2019ll keep it simple with Maps and Closures. We\u2019ll first write a
-helper method:
-
-[source,groovy]
-------------------------------------------------------------------------------------------------------
-def split(string) {
-  [on: { sep ->
-    [trimming: { trimChar ->
-      Splitter.on(sep).trimResults(CharMatcher.is(trimChar as char)).split(string).iterator().toList()
-    }]
-  }]
-}
-------------------------------------------------------------------------------------------------------
-
-now instead of this line from our original example:
-
-[source,groovy]
-----------------------------------------------------------------------------------------------------------------
-def result = Splitter.on(',').trimResults(CharMatcher.is('_' as char)).split("_a ,_b_ ,c__").iterator().toList()
-----------------------------------------------------------------------------------------------------------------
-
-we can write this:
-
-[source,groovy]
------------------------------------------------------
-def result = split "_a ,_b_ ,c__" on ',' trimming '_'
------------------------------------------------------
-
-[[Groovy18releasenotes-Performanceimprovements]]
-== Performance improvements
-
-Groovy\u2019s flexible metaprogramming model involves numerous decision
-points when making method calls or accessing properties to determine
-whether any metaprogamming hooks are being utilized. During complex
-expression calculations, such decision points involved identical checks
-being executed numerous times. Recent performance improvements allow
-some of these checks to be bypassed during an expression calculation
-once certain initial assumptions have been checked. Basically if certain
-preconditions hold, some streamlining can take place.
-
-Groovy 1.8.0 contains two main streams of optimization work:
-
-* There are several optimizations for basic operations on integers like
-plus, minus, multiply, increment, decrement and comparisons. This
-version doesn\u2019t support the mixed usage of different types. If an
-expression contains different types, then it falls back to the classical
-way of performing the operation, i.e. no streamlining occurs.
-* There is also an optimization for direct method calls. Such a method
-call is done directly if it is done on `this` and if the argument
-types are a direct match with the parameter types of the method we may
-call. Since this is an operation that does not behave too well with a
-method call logic based on runtime types we select only methods where
-the primitive types match, the parameter types are final or for methods
-that take no arguments. Currently methods with a variable parameter list
-are not matched in general, unless a fitting array is used for the
-method call.
-
-Those two areas of optimization are only the beginning of further
-similar improvements. Upcoming versions of the Groovy 1.8.x branch will
-see more optimizations coming. In particular, primitive types other than
-integers should be expected to be supported shortly.
-
-[[Groovy18releasenotes-GParsbundledwithintheGroovydistribution]]
-== GPars bundled within the Groovy distribution
-
-The http://gpars.github.io[GPars] project offers developers new
-intuitive and safe ways to handle Java or Groovy tasks concurrently,
-asynchronously, and distributed by utilizing the power of the Java
-platform and the flexibility of the Groovy language. Groovy 1.8 now
-bundles GPars 0.11 in the libraries of the Groovy installation, so that
-you can leverage all the features of the library for +
- Fork/Join, Map/Filter/Reduce, DataFlow, Actors, Agents, and more with
-all the Groovy goodness.
-
-To learn more about GPars, head over to the
-http://gpars.github.io/[GPars website], read the
-http://gpars.org/guide/index.html[detailed online user guide], or check
-out chapter 17 of http://www.manning.com/koenig2[Groovy in Action, 2nd
-Edition (MEAP)].
-
-[[Groovy18releasenotes-Closureenhancements]]
-== Closure enhancements
-
-Closures are a central and essential piece of the Groovy programming
-language and are used in various ways throughout the Groovy APIs. In
-Groovy 1.8, we introduce the ability to use closures as annotation
-parameters. Closures are also a key part of what gives Groovy its
-functional flavor.
-
-[[Groovy18releasenotes-Closureannotationparameters]]
-=== Closure annotation parameters
-
-In Java, there\u2019s a limited set of types you can use as annotation
-parameters (String, primitives, annotations, classes, and arrays of
-these). But in Groovy 1.8, we\u2019re going further and let you use closures
-as annotation parameters \u2013 which are actually transformed into a class
-parameter for compatibility reasons.
-
-[source,groovy]
-------------------------------------------------
-import java.lang.annotation.*
-
-@Retention(RetentionPolicy.RUNTIME)
-@interface Invariant {
-    Class value() // will hold a closure class
-}
-
-@Invariant({ number >= 0 })
-class Distance {
-    float number
-    String unit
-}
-
-def d = new Distance(number: 10, unit: "meters")
-
-def anno = Distance.getAnnotation(Invariant)
-def check = anno.value().newInstance(d, d)
-
-assert check(d)
-------------------------------------------------
-
-Closure annotation parameters open up some interesting possibilities for
-framework authors! As an example, the
-https://github.com/andresteingress/gcontracts/wiki/[GContracts] project,
-which brings the `Design by Contract` paradigm to Groovy makes heavy
-use of annotation parameters to allow preconditions, postconditions and
-invariants to be declared.
-
-[[Groovy18releasenotes-Closurefunctionalflavors]]
-=== Closure functional flavors
-
-[[Groovy18releasenotes-Closurecomposition]]
-==== Closure composition
-
-If you recall your math lessons, function composition may be a concept
-you\u2019re familiar with. And in turn, *Closure composition* is about that:
-the ability to compose Closures together to form a new Closure which
-chains the call of those Closures. Here\u2019s an example of composition in
-action:
-
-[source,groovy]
----------------------------------------------
-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)
----------------------------------------------
-
-To see more examples of Closure composition and reverse composition,
-please have a look at our
-https://github.com/apache/groovy/blob/master/src/test/groovy/ClosureComposeTest.groovy[test
-case].
-
-[[Groovy18releasenotes-Closuretrampoline]]
-==== Closure trampoline
-
-When writing recursive algorithms, you may be getting the infamous stack
-overflow exceptions, as the stack starts to have a too high depth of
-recursive calls. An approach that helps in those situations is by using
-Closures and their new
-http://en.wikipedia.org/wiki/Tail_call#Through_trampolining[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\u2019s an example of the use of `trampoline()` to implement the
-factorial function:
-
-[source,groovy]
-------------------------------------------------------------------
-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
-------------------------------------------------------------------
-
-[[Groovy18releasenotes-Closurememoization]]
-==== Closure memoization
-
-Another improvement to Closures is the ability to
-http://en.wikipedia.org/wiki/Memoization[memoize] the outcome of
-previous (ideally side-effect free) invocations of your Closures. The
-return values for a given set of Closure parameter values are kept in a
-cache, for those memoized Closures. That way, if you have an expensive
-computation to make that takes seconds, you can put the return value in
-cache, so that the next execution with the same parameter will return
-the same result \u2013 again, we assume results of an invocation are the same
-given the same set of parameter values.
-
-There are three forms of memoize functions:
-
-* the standard `memoize()` which caches all the invocations
-* `memoizeAtMost(max)` call which caches a maximum number of invocations
-* `memoizeAtLeast(min)` call which keeps at least a certain number of
-invocation results
-* and `memoizeBetween(min, max)` which keeps a range results (between a
-minimum and a maximum)
-
-Let\u2019s illustrate that:
-
-[source,groovy]
---------------------------------------------------
-def plus = { a, b -> sleep 1000; a + b }.memoize()
-assert plus(1, 2) == 3 // after 1000ms
-assert plus(1, 2) == 3 // return immediately
-assert plus(2, 2) == 4 // after 1000ms
-assert plus(2, 2) == 4 // return immediately
-�
-// other forms:
-
-// at least 10 invocations cached
-def plusAtLeast = { ... }.memoizeAtLeast(10)
-
-// at most 10 invocations cached
-def plusAtMost = { ... }.memoizeAtMost(10)
-
-// between 10 and 20 invocations cached
-def plusAtLeast = { ... }.memoizeBetween(10, 20)
---------------------------------------------------
-
-[[Groovy18releasenotes-Curryingimprovements]]
-=== Currying improvements
-
-Currying improvements have also been backported to recent releases of
-Groovy 1.7, but it\u2019s worth outlining here for reference. Currying used
-to be done only from left to right, but it\u2019s also possible to do it from
-right to left, or from a given index, as the following examples
-demonstrate:
-
-[source,groovy]
-------------------------------------------
-// right currying
-def divide = { a, b -> a / b }
-def halver = divide.rcurry(2)
-assert halver(8) == 4
-�
-// currying n-th parameter
-def joinWithSeparator = { one, sep, two ->
-    one + sep + two
-}
-def joinWithComma =
-    joinWithSeparator.ncurry(1, ', ')
-assert joinWithComma('a', 'b') == 'a, b'
-------------------------------------------
-
-[[Groovy18releasenotes-NativeJSONsupport]]
-== Native JSON support
-
-With the ubiquity of JSON as an interchange format for our applications,
-it is natural that Groovy added support for JSON, in a similar fashion
-as the support Groovy\u2019s always had with XML. So Groovy 1.8 introduces a
-JSON builder and parser.
-
-[[Groovy18releasenotes-ReadingJSON]]
-=== Reading JSON
-
-A `JsonSlurper` class allows you to parse JSON payloads, and access the
-nested Map and List data structures representing that content. JSON
-objects and arrays are indeed simply represented as Maps and Lists,
-giving you access to all the GPath expression benefits
-(subscript/property notation, find/findAll/each/inject/groupBy/etc.).
-Here\u2019s an example showing how to find all the recent commit messages on
-the Grails project:
-
-[source,groovy]
---------------------------------------------------------------------------------------------------
-import groovy.json.*
-
-def payload = new URL("http://github.com/api/v2/json/commits/list/grails/grails-core/master").text
-
-def slurper = new JsonSlurper()
-def doc = slurper.parseText(payload)
-
-doc.commits.message.each { println it }
---------------------------------------------------------------------------------------------------
-
-If you want to see some more examples of the usage of the JSON parser,
-you can have a look at the
-https://github.com/apache/groovy/blob/master/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy[JsonSlurper
-tests] in our code base.
-
-[[Groovy18releasenotes-JSONbuilder]]
-=== JSON builder
-
-Parsing JSON data structures is one thing, but we should also be able to
-produce JSON content just like we create markup with the
-`MarkupBuilder`. The following example:
-
-[source,groovy]
-----------------------------
-import groovy.json.*
-
-def json = new JsonBuilder()
-
-json.person {
-    name "Guillaume"
-    age 33
-    pets "Hector", "Felix"
-}
-
-println json.toString()
-----------------------------
-
-Will create the JSON output:
-
-[source,groovy]
-------------------------------------------------------------------
-{"person":{"name":"Guillaume","age":33,"pets":["Hector","Felix"]}}
-------------------------------------------------------------------
-
-You can find some more usages of the JSON builder in our
-https://github.com/apache/groovy/blob/master/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy[JsonBuilder
-tests].
-
-[[Groovy18releasenotes-PrettyprintingJSONcontent]]
-=== Pretty printing JSON content
-
-When given a JSON data structure, you may wish to pretty-print it, so
-that you can more easily inspect it, with a more friendly layout. So for
-instance, if you want to pretty print the result of the previous
-example, you could do:
-
-[source,groovy]
---------------------------------------------------------------------------------------------------------------------
-import groovy.json.*
-
-println JsonOutput.prettyPrint('''{"person":{"name":"Guillaume","age":33,"pets":["Hector","Felix"]}}''')\u200b\u200b\u200b\u200b\u200b\u200b\u200b\u200b\u200b\u200b\u200b\u200b
---------------------------------------------------------------------------------------------------------------------
-
-Which would result in the following pretty-printed output:
-
-[source,groovy]
-----------------------------
-{
-    "person": {
-        "name": "Guillaume",
-        "age": 33,
-        "pets": [
-            "Hector",
-            "Felix"
-        ]
-    }
-}
-----------------------------
-
-[[Groovy18releasenotes-NewASTTransformations]]
-== New AST Transformations
-
-The Groovy compiler reads the source code, builds an Abstract Syntax
-Tree (AST) from it, and then puts the AST into bytecode. With AST
-transformations, the programmer can hook into this process. A general
-description of this process, an exhaustive description of all available
-transformations, and a guide of how to write you own ones can be found
-for example in http://www.manning.com/koenig2[Groovy in Action, 2nd
-Edition (MEAP)], chapter 9.
-
-Below is a list of all new transformations that come with Groovy 1.8.
-They save you from writing repetitive code and help avoiding common
-errors.
-
-[[Groovy18releasenotes-Log]]
-=== @Log
-
-You can annotate your classes with the @Log transformation to
-automatically inject a logger in your Groovy classes, under the `log`
-property. Four kind of loggers are actually available:
-
-* `@Log` for java.util.logging
-* `@Commons` for Commons-Logging
-* `@Log4j` for Log4J
-* `@Slf4j` for SLF4J
-
-Here\u2019s a sample usage of the @Log transformation:
-
-[source,groovy]
-----------------------------------
-import groovy.util.logging.*
-
-@Log
-class Car {
-    Car() {
-        log.info 'Car constructed'
-    }
-}
-
-def c = new Car()
-----------------------------------
-
-You can change the name of the logger by specifying a different name,
-for instance with `@Log('myLoggerName')`.
-
-Another particularity of these logger AST transformations is that they
-take care of wrapping and safe-guarding logger calls with the usual
-`isSomeLevelEnabled()` calls. So when you write
-`log.info 'Car constructed'`, the generated code is actually equivalent
-to:
-
-[source,groovy]
----------------------------------
-if (log.isLoggable(Level.INFO)) {
-    log.info 'Car constructed'
-}
----------------------------------
-
-[[Groovy18releasenotes-Field]]
-=== @Field
-
-When defining variables in a script, those variables are actually local
-to the script\u2019s run method, so they are not accessible from other
-methods of the script. A usual approach to that problem has been to
-store variables in the binding, by not def\u2019ining those variables and by
-just assigning them a value. Fortunately, the `@Field` transformation
-provides a better alternative: by annotating your variables in your
-script with this annotation, the annotated variable will become a
-private field of the script class.
-
-More concretely, you\u2019ll be able to do as follows:
-
-[source,groovy]
----------------------------
-@Field List awe = [1, 2, 3]
-def awesum() { awe.sum() }
-assert awesum() == 6
----------------------------
-
-[[Groovy18releasenotes-PackageScopeenhancements]]
-=== @PackageScope enhancements
-
-The @PackageScope annotation can be placed on classes, methods or fields
-and is used for turning off Groovy\u2019s visibility conventions and
-reverting back to Java conventions. This ability is usually only needed
-when using 3rd party libraries which rely on the package scope
-visibility. When adding the `@PackageScope` annotation to a field,
-Groovy will assign package scope access to the field rather than
-automatically treating it as a property (and adding setters/getters).
-Annotating a class or method with `@PackageScope` will cause Groovy to
-revert to Java\u2019s convention of leaving the class/method as package
-scoped rather than automatically promoting it to public scope. The class
-variant can also take one or more parameters to allow nested setting of
-visibility of attributes within the class - see the Javadoc for more
-details. Recent releases of Groovy 1.7 have had a more limited version
-of this annotation.
-
-[[Groovy18releasenotes-AutoClone]]
-=== @AutoClone
-
-The `@AutoClone` annotation is placed on classes which you want to be
-`Cloneable`. The annotation instructs the compiler to execute an AST
-transformation which adds a public `clone()` method and adds `Cloneable`
-to the classes implements list of interfaces. Because the JVM doesn\u2019t
-have a one-size-fits-all cloning strategy, several customizations exist
-for the cloning implementation:
-
-* By default, the `clone()` method will call `super.clone()` before
-calling `clone()` on each `Cloneable` property of the class. Example
-usage:
-
-[source,groovy]
----------------------------------
-import groovy.transform.AutoClone
-
-@AutoClone
-class Person {
-    String first, last
-    List favItems
-    Date since
-}
----------------------------------
-
-Which will create a class of the following form:
-
-[source,groovy]
--------------------------------------------------------------
-class Person implements Cloneable {
-    ...
-    public Object clone() throws CloneNotSupportedException {
-        Object result = super.clone()
-        result.favItems = favItems.clone()
-        result.since = since.clone()
-        return result
-    }
-    ...
-}
--------------------------------------------------------------
-
-
-* Another popular cloning strategy is known as the copy constructor
-pattern. If any of your fields are `final` and `Cloneable` you should
-set `style=COPY_CONSTRUCTOR` which will then use the copy constructor
-pattern.
-* As a final alternative, if your class already implements the
-`Serializable` or `Externalizable` interface, you might like to set
-`style=SERIALIZATION` which will then use serialization to do the
-cloning.
-
-See the Javadoc for `AutoClone` for further details.
-
-[[Groovy18releasenotes-AutoExternalizable]]
-=== @AutoExternalizable
-
-The `@AutoExternalizable` class annotation is used to assist in the
-creation of `Externalizable` classes. The annotation instructs the
-compiler to execute an AST transformation which adds `writeExternal()`
-and `readExternal()` methods to a class and adds `Externalizable` to the
-interfaces which the class implements. The `writeExternal()` method
-writes each property (or field) for the class while the `readExternal()`
-method will read each one back in the same order. Properties or fields
-marked as `transient` are ignored. Example usage:
-
-[source,groovy]
--------------------------
-import groovy.transform.*
-
-@AutoExternalize
-class Person {
-    String first, last
-    List favItems
-    Date since
-}
--------------------------
-
-Which will create a class of the following form:
-
-[source,groovy]
--------------------------------------------------------------
-class Person implements Externalizable {
-    ...
-    void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(first)
-        out.writeObject(last)
-        out.writeObject(favItems)
-        out.writeObject(since)
-    }
-
-    void readExternal(ObjectInput oin) {
-        first = oin.readObject()
-        last = oin.readObject()
-        favItems = oin.readObject()
-        since = oin.readObject()
-    }
-    ...
-}
--------------------------------------------------------------
-
-[[Groovy18releasenotes-Controllingtheexecutionofyourcode]]
-=== Controlling the execution of your code
-
-When integrating user-provided Groovy scripts and classes in your Java
-application, you may be worried about code that would eat all your CPU
-with infinite loops, or that call methods like `System.exit(0)` (for the
-latter, check the section on compiler customizers, and particularly the
-`SecureASTCustomizer`). It would be interesting to have a wait to
-control the execution of that Groovy code, to be able to interrupt its
-execution when the thread is interrupted, when a certain duration has
-elapsed, or when a certain condition is met (lack of resources, etc).
-
-Groovy 1.8 introduces three transformations for those purposes, as we
-shall see in the following sections. By default, the three
-transformations add some checks in at the beginning of each method body,
-and each closure body, to check whether a condition of interruption is
-met or not.
-
-Note that those transformations are local (triggered by an annotation).
-If you want to apply them transparently, so that the annotation doesn\u2019t
-show up, I encourage you to have a look at the
-`ASTTransformationCustomizer` explained at the end of this article.
-
-C�dric Champeau, our most recent Groovy committer, who implemented those
-features, has a
-http://www.jroller.com/melix/entry/upcoming_groovy_goodness_automatic_thread[very
-nice blog post] covering those code interruption transformations.
-
-[[Groovy18releasenotes-ThreadInterrupt]]
-==== @ThreadInterrupt
-
-You don\u2019t need to write checks in your scripts for whether the current
-thread of execution has been interrupted or not, by default, the
-transformation will add those checks for you for scripts and classes, at
-the beginning of each method body and closure body:
-
-[source,groovy]
----------------------------------------
-@ThreadInterrupt
-import groovy.transform.ThreadInterrupt
-
-while (true) {
-    // eat lots of CPU
-}
----------------------------------------
-
-You can specify a `checkOnMethodStart` annotation parameter (defaults to
-true) to customize where checks are added by the transformation (adds an
-interrupt check by default as the first statement of a method body). And
-you can also specify the `applyToAllClasses` annotation parameter
-(default to true) if you want to specify whether only the current class
-or script should have this interruption logic applied or not.
-
-[[Groovy18releasenotes-TimedInterrupt]]
-==== @TimedInterrupt
-
-With `@TimedInterrupt`, you can interrupt the script after a certain
-amount of time:
-
-[source,groovy]
---------------------------------------
-@TimedInterrupt(10)
-import groovy.transform.TimedInterrupt
-
-while (true) {
-    // eat lots of CPU
-}
---------------------------------------
-
-In addition to the previous annotation parameters we mentioned for
-`@ThreadInterrupt`, you should specify `value`, the amount of time to
-wait, and `unit` (defaulting to `TimeUnit.SECONDS`) to specify the unit
-of time to be used.
-
-[[Groovy18releasenotes-ConditionalInterrupt]]
-==== @ConditionalInterrupt
-
-An example of `@ConditionalInterrupt` which leverages the closure
-annotation parameter feature, and the `@Field` transformation as well:
-
-[source,groovy]
---------------------------------------------
-@ConditionalInterrupt({ counter++ > 2 })
-import groovy.transform.ConditionalInterrupt
-import groovy.transform.Field
-
-@Field int counter = 0
-
-100.times {
-    println 'executing script method...'
-}
---------------------------------------------
-
-You can imagine defining any kind of condition: on counters, on resource
-availability, on resource usage, and more.
-
-[[Groovy18releasenotes-ToString]]
-=== @ToString
-
-Provides your classes with a default `toString()` method which prints
-out the values of the class\u2019 properties (and optionally the property
-names and optionally fields). A basic example is here:
-
-[source,groovy]
------------------------------------------
-import groovy.transform.ToString
-
-@ToString
-class Person {
-    String name
-    int age
-}
-
-println new Person(name: 'Pete', age: 15)
-// => Person(Pete, 15)
------------------------------------------
-
-And here\u2019s another example using a few more options:
-
-[source,groovy]
-----------------------------------------------------
-@ToString(includeNames = true, includeFields = true)
-class Coord {
-    int x, y
-    private z = 0
-}
-println new Coord(x:20, y:5)
-// => Coord(x:20, y:5, z:0)
-----------------------------------------------------
-
-[[Groovy18releasenotes-EqualsAndHashCode]]
-=== @EqualsAndHashCode
-
-Provides your classes with `equals()` and `hashCode()` methods based on
-the values of the class\u2019 properties (and optionally fields and
-optionally super class values for `equals()` and `hashCode()`).
-
-[source,groovy]
------------------------------------------
-import groovy.transform.EqualsAndHashCode
-
-@EqualsAndHashCode
-class Coord {
-    int x, y
-}
-
-def c1 = new Coord(x:20, y:5)
-def c2 = new Coord(x:20, y:5)
-
-assert c1 == c2
-assert c1.hashCode() == c2.hashCode()
------------------------------------------
-
-[[Groovy18releasenotes-TupleConstructor]]
-=== @TupleConstructor
-
-Provides a tuple (ordered) constructor. For POGOs (plain old Groovy
-objects), this will be in addition to Groovy\u2019s default `named-arg`
-constructor.
-
-[source,groovy]
----------------------------------------------------------
-import groovy.transform.TupleConstructor
-
-@TupleConstructor
-class Person {
-    String name
-    int age
-}
-
-def p1 = new Person(name: 'Pete', age: 15) // map-based
-def p2 = new Person('Pete', 15)            // tuple-based
-
-assert p1.name == p2.name
-assert p1.age == p2.age
----------------------------------------------------------
-
-[[Groovy18releasenotes-Canonical]]
-=== @Canonical
-
-Allows you to combine `@ToString`, `@EqualsAndHashCode` and
-`@TupleConstructor`. For those familiar with Groovy\u2019s `@Immutable`
-transform, this provides similar features but for mutable objects.
-
-[source,groovy]
---------------------------------------------
-import groovy.transform.Canonical
-
-@Canonical
-class Person {
-    String name
-    int age
-}
-
-def p1 = new Person(name: 'Pete', age: 15)
-def p2 = new Person('Paul', 15)
-
-p2.name = 'Pete'
-println "${p1.equals(p2)} $p1 $p2"
-// => true Person(Pete, 15) Person(Pete, 15)
---------------------------------------------
-
-By default, `@Canonical` gives you vanilla versions for each of the
-combined annotations. If you want to use any of the special features
-that the individual annotations give you, simply include the individual
-annotation as well.
-
-[source,groovy]
------------------------------------------
-import groovy.transform.*
-
-@Canonical
-@ToString(includeNames = true)
-class Person {
-    String name
-    int age
-}
-
-def p = new Person(name: 'Pete', age: 15)
-println p
-// => Person(name:Pete, age:15)
------------------------------------------
-
-You will find a great
-http://prystash.blogspot.com/2011/04/groovy-18-playing-with-new-canonical.html[write-up
-on @Canonical, @ToString, @EqualsAndHashCode and @TupleConstructor] on
-John Prystash\u2019s weblog.
-
-[[Groovy18releasenotes-InheritConstructors]]
-=== @InheritConstructors
-
-Sometimes, when you want to subclass certain classes, you also need to
-override all the constructors of the parent, even if only to call the
-super constructor. Such a case happens for instance when you define your
-own exceptions, you want your exceptions to also have the constructors
-taking messages and throwable as parameters. But instead of writing this
-kind of boilerplate code each time for your exceptions:
-
-[source,groovy]
---------------------------------------------------------------
-class CustomException extends Exception {
-    CustomException() { super() }
-    CustomException(String msg) { super(msg) }
-    CustomException(String msg, Throwable t) { super(msg, t) }
-    CustomException(Throwable t) { super(t) }
-}
---------------------------------------------------------------
-
-Simply use the @InheritConstructors transformation which takes care of
-overriding the base constructors for you:
-
-[source,groovy]
-------------------------------------------
-import groovy.transform.*
-
-@InheritConstructors
-class CustomException extends Exception {}
-------------------------------------------
-
-[[Groovy18releasenotes-WithReadLockandWithWriteLock]]
-=== @WithReadLock and @WithWriteLock
-
-Those two transformations, combined together, simplify the usage of
-`java.util.concurrent.locks.ReentrantReadWriteLock`, are safer to use
-than the `synchronized` keyword, and improve upon the `@Synchronized`
-transformation with a more granular locking.
-
-More concretely, with an example, the following:
-
-[source,groovy]
-------------------------------------------------------------
-import groovy.transform.*
-
-class ResourceProvider {
-    private final Map<String, String> data = new HashMap<>()
-
-    @WithReadLock
-    String getResource(String key) {
-        return data.get(key)
-    }
-
-    @WithWriteLock
-    void refresh() {
-        //reload the resources into memory
-    }
-}
-------------------------------------------------------------
-
-Will generate code as follows:
-
-[source,groovy]
------------------------------------------------------------------------------
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import java.util.concurrent.locks.ReadWriteLock
-
-class ResourceProvider {
-    private final ReadWriteLock $reentrantlock = new ReentrantReadWriteLock()
-    private final Map<String, String> data = new HashMap<String, String>()
-
-    String getResource(String key) {
-        $reentrantlock.readLock().lock()
-        try {
-            return data.get(key)
-        } finally {
-            $reentrantlock.readLock().unlock()
-        }
-    }
-
-    void refresh() throws Exception {
-        $reentrantlock.writeLock().lock()
-        try {
-            //reload the resources into memory
-        } finally {
-            $reentrantlock.writeLock().unlock()
-        }
-    }
-}
------------------------------------------------------------------------------
-
-[[Groovy18releasenotes-ListenerList]]
-=== @ListenerList
-
-If you annotate a Collection type field with @ListenerList, it generates
-everything that is needed to follow the bean event pattern. This is kind
-of an EventType independent version of what @Bindable is for
-PropertyChangeEvents.
-
-This example shows the most basic usage of the @ListenerList annotation.
-The easiest way to use this annotation is to annotate a field of type
-List and give the List a generic type. In this example we use a List of
-type MyListener. MyListener is a one method interface that takes a
-MyEvent as a parameter. The following code is some sample source code
-showing the simplest scenario.
-
-[source,groovy]
------------------------------------------
-interface MyListener {
-    void eventOccurred(MyEvent event)
-}
-
-class MyEvent {
-    def source
-    String message
-
-    MyEvent(def source, String message) {
-        this.source = source
-        this.message = message
-    }
-}
-class MyBeanClass {
-    @ListenerList
-    List<MyListener> listeners
-}
------------------------------------------
-
-* + addMyListener(MyListener) : void - This method is created based on
-the generic type of your annotated List field. The name and parameter
-type is are based on the List field\u2019s generic parameter.
-* + removeMyListener(MyListener) : void- This method is created based on
-the generic type of your annotated List field. The name and parameter
-type is are based on the List field\u2019s generic parameter.
-* + getMyListeners() : MyListener[] - This method is created based on
-the generic type of your annotated List field.The name is the plural
-form of the List field\u2019s generic parameter, and the return type is an
-array of the generic parameter.
-* + fireEventOccurred(MyEvent) : void - This method is created based on
-the type that the List\u2019s generic type points to. In this case,
-MyListener is a one method interface with an eventOccurred(MyEvent)
-method. The method name is fire[MethodName of the interface] and the
-parameter is the parameter list from the interface. A fireX method will
-be generated for each public method in the target class, including
-overloaded methods.�
-
-[[Groovy18releasenotes-AlignmentswithJDK7]]
-== Alignments with JDK 7
-
-Groovy 1.9 will be the version which will align as much as possible with
-the upcoming JDK 7, so beyond those aspects already covered in Groovy
-(like strings in switch and others), most of those `Project Coin`
-proposals will be in 1.9, except the `diamond operator` which was
-added in 1.8, as explained in the following paragraph.
-
-[[Groovy18releasenotes-Diamondoperator]]
-=== Diamond operator
-
-Java 7 will introduce the `diamond` operator in generics type
-information, so that you can avoid the usual repetition of the
-parameterized types. Groovy decided to adopt the notation before JDK 7
-is actually released. So instead of writing:
-
-[source,groovy]
---------------------------------------------------------
-List<List<String>> list1 = new ArrayList<List<String>>()
---------------------------------------------------------
-
-You can _omit_ the parameterized types and just use the pointy
-brackets, which now look like a diamond:
-
-[source,groovy]
---------------------------------------------
-List<List<String>> list1 = new ArrayList<>()
---------------------------------------------
-
-[[Groovy18releasenotes-NewDGMmethods]]
-== New DGM methods
-
-* count Closure variants
-
-[source,groovy]
----------------------------------------------
-def isEven = { it % 2 == 0 }
-assert [2,4,2,1,3,5,2,4,3].count(isEven) == 5
----------------------------------------------
-
-* countBy
-
-[source,groovy]
-----------------------------------------------------------------------
-assert [0:2, 1:3] == [1,2,3,4,5].countBy{ it % 2 }
-assert [(true):2, (false):4] == 'Groovy'.toList().countBy{ it == 'o' }
-----------------------------------------------------------------------
-
-* plus variants specifying a starting index
-
-[source,groovy]
--------------------------------------------------------
-assert [10, 20].plus(1, 'a', 'b') == [10, 'a', 'b', 20]
--------------------------------------------------------
-
-* equals for Sets and Maps now do flexible numeric comparisons (on
-values for Maps)
-
-[source,groovy]
-----------------------------------------
-assert [1L, 2.0] as Set == [1, 2] as Set
-assert [a:2, b:3] == [a:2L, b:3.0]
-----------------------------------------
-
-* toSet for primitive arrays, Strings and Collections
-
-[source,groovy]
------------------------------------------------------------
-assert [1, 2, 2, 2, 3].toSet() == [1, 2, 3] as Set
-assert 'groovy'.toSet() == ['v', 'g', 'r', 'o', 'y'] as Set
------------------------------------------------------------
-
-* min / max methods for maps taking closures +
- (also available in Groovy 1.7)
-
-[source,groovy]
-----------------------------------------------
-def map = [a: 1, bbb: 4, cc: 5, dddd: 2]
-
-assert map.max { it.key.size() }.key == 'dddd'
-assert map.min { it.value }.value == 1
-----------------------------------------------
-
-* map withDefault\{} +
- Oftentimes, when using a map, for example for counting the frequency of
-words in a document, you need to check that a certain key exists, before
-doing something with the associating value (like incrementing it).
-Nothing really complex, but we could improve upon that with a new
-method, called `withDefault`. So instead of writing code like below:
-
-[source,groovy]
----------------------------------------------------
-def words = "one two two three three three".split()
-def freq = [:]
-words.each {
-    if (it in freq)
-        freq[it] += 1
-    else
-        freq[it] = 1
-}
----------------------------------------------------
-
-Thanks to the new method (also backported to 1.7), you can write the
-example as follows:
-
-[source,groovy]
----------------------------------------------------
-def words = "one two two three three three".split()
-def freq = [:].withDefault { k -> 0 }
-words.each {
-        freq[it] += 1
-}
----------------------------------------------------
-
-[[Groovy18releasenotes-Miscellaneous]]
-== Miscellaneous
-
-[[Groovy18releasenotes-Slashystrings]]
-=== Slashy strings
-
-Slashy strings are now multi-line:
-
-[source,groovy]
------------------------------------
-def poem = /
-to be
-or
-not to be
-/
-
-assert poem.readLines().size() == 4
------------------------------------
-
-This is particularly useful for multi-line regexs when using the regex
-free-spacing comment style (though you would still need to escape
-slashes):
-
-[source,groovy]
--------------------------------------------------------------------------------------------
-// match yyyy-mm-dd from this or previous century
-def dateRegex = /(?x)     # enable whitespace and comments
-((?:19|20)\d\d)           # year (group 1) (non-capture alternation for century)
--                         # seperator
-(0[1-9]|1[012])           # month (group 2)
--                         # seperator
-(0[1-9]|[12][0-9]|3[01])  # day (group 3)
-/
-
-assert '04/04/1988' == '1988-04-04'.find(dateRegex) { all, y, m, d -> [d, m, y].join('/') }
--------------------------------------------------------------------------------------------
-
-[[Groovy18releasenotes-Dollarslashystrings]]
-=== Dollar slashy strings
-
-A new string notation has been introduced: the `dollar slashy` string.
-This is a multi-line GString similar to the slashy string, but with
-slightly different escaping rules. You are no longer required to escape
-slash (with a preceding backslash) but you can use `$$' to escape a `$'
-or `$/' to escape a slash if needed. Here\u2019s an example of its usage:
-
-[source,groovy]
-------------------------
-def name = "Guillaume"
-def date = "April, 21st"
-
-def dollarSlashy = $/
-    Hello $name,
-    today we're ${date}
-    $ dollar-sign
-    $$ dollar-sign
-    \ backslash
-    / slash
-    $/ slash
-/$
-
-println dollarSlashy
-------------------------
-
-This form of string is typically used when you wish to embed content
-that may naturally contains slashes or backslashes and you don\u2019t want to
-have to rework the content to include all of the necessary escaping.
-Some examples are shown below:
-
-* Embedded XML fragments with backslashes:
-
-[source,groovy]
--------------------------------------------
-def tic = 'tic'
-
-def xml = $/
-  <xml>
-  $tic\tac
-  </xml>
-/$
-
-assert "\n<xml>\ntic\\tac\n</xml>\n" == xml
--------------------------------------------
-
-Better than a normal (now multi-line) slashy string where you would have
-to escape the slashes or a triple quote (``'''``) GString where you would
-have to escape the backslashes.
-
-* Or windows pathnames containing a slash at the end:
-
-[source,groovy]
-----------------------
-def dir = $/C:\temp\/$
-----------------------
-
-Previously, triple quote (`'''`) GString required extra escaping, and
-the above sequence was illegal for a normal slashy string. Now, ugly
-workarounds are not needed.
-
-* Embedding multi-line regexs when using the regex free-spacing comment
-style (particularly ones which contain slashes):
-
-[source,groovy]
--------------------------------------------------------------------------------------------
-// match yyyy-mm-dd from current or previous century
-def dateRegex = $/(?x)    # enable whitespace and comments
-((?:19|20)\d\d)           # year (group 1) (non-capture alternation for century)
-[- /.]                    # seperator
-(0[1-9]|1[012])           # month (group 2)
-[- /.]                    # seperator
-(0[1-9]|[12][0-9]|3[01])  # day (group 3)
-/$
-
-assert '04/04/1988' == '1988-04-04'.find(dateRegex) { all, y, m, d -> [d, m, y].join('/') }
-assert '10-08-1989' == '1989/08/10'.find(dateRegex) { all, y, m, d -> [d, m, y].join('-') }
--------------------------------------------------------------------------------------------
-
-So, you can cut and paste most PERL regex examples without further
-escaping.
-
-* Or Strings which are themselves Groovy code fragments containing
-slashes:
-
-[source,groovy]
------------------------------------
-def alphabet = ('a'..'z').join('')
-def code = $/
-    def normal = '\b\t\n\r'
-    def slashy = /\b\t\n\r/
-    assert '$alphabet'.size() == 26
-    assert normal.size() == 4
-    assert slashy.size() == 8
-/$
-println code
-Eval.me(code)
------------------------------------
-
-Again allowing you to cut and paste many slashy string Groovy examples
-and have them embedded within dollar slashy strings without further
-escaping.
-
-[[Groovy18releasenotes-Compilationcustomizers]]
-=== Compilation customizers
-
-The compilation of Groovy code can be configured through the
-`CompilerConfiguration` class, for example for setting the encoding of
-your sources, the base script class, the recompilation parameters, etc).
-`CompilerConfiguration` now has a new option for setting _compilation
-customizers_ (belonging to the `org.codehaus.groovy.control.customizers`
-package). Those customizers allow to customize the compilation process
-in three ways:
-
-* adding default imports with the `ImportCustomizer`: so you don\u2019t have
-to always add the same imports all over again
-* securing your scripts and classes with the `SecureASTCustomizer`: by
-allowing/disallowing certain classes, or special AST nodes (Abstract
-Syntax Tree), filtering imports, you can secure your scripts to avoid
-malicious code or code that would go beyond the limits of what the code
-should be allowed to do.
-* applying AST transformations with the `ASTTransformationCustomizer`:
-lets you apply transformations to all the class nodes of your
-compilation unit.
-
-For example, if you want to apply the @Log transformation to all the
-classes and scripts, you could do:
-
-[source,groovy]
------------------------------------------------------------------------------
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.*
-import groovy.util.logging.Log
-
-def configuration = new CompilerConfiguration()
-configuration.addCompilationCustomizers(new ASTTransformationCustomizer(Log))
-
-def shell = new GroovyShell(configuration)
-shell.evaluate("""
-    class Car {
-        Car() {
-            log.info 'Car constructed'
-        }
-    }
-
-    log.info 'Constructing a car'
-    def c = new Car()
-""")
------------------------------------------------------------------------------
-
-This will log the two messages, the one from the script, and the one
-from the Car class constructor, through java.util.logging. No need to
-apply the @Log transformation manually to both the script and the class:
-the transformation is applied to all class nodes transparently. This
-mechanism can also be used for adding global transformations, just for
-the classes and scripts that you compile, instead of those global
-transformations being applied to all scripts and classes globally.
-
-If you want to add some default imports (single import, static import,
-star import, star static imports, and also aliased imports and static
-imports), you can use the import customizer as follows:
-
-[source,groovy]
---------------------------------------------------------
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.*
-
-def configuration = new CompilerConfiguration()
-def custo = new ImportCustomizer()
-custo.addStaticStar(Math.name)
-configuration.addCompilationCustomizers(custo)
-
-def shell = new GroovyShell(configuration)
-shell.evaluate("""
-    cos PI/3
-""")
---------------------------------------------------------
-
-When you want to evaluate Math expressions, you don\u2019t need anymore to
-use the `import static java.lang.Math.*` star static import to import
-all the Math constants and static functions.
-
-[[Groovy18releasenotes-GStringtoEnumcoercion]]
-=== (G)String to Enum coercion
-
-Given a String or a GString, you can coerce it to Enum values bearing
-the same name, as the sample below presents:
-
-[source,groovy]
------------------------------
-enum Color {
-    red, green, blue
-}
-
-// coercion with as
-def r = "red" as Color
-
-// implicit coercion
-Color b = "blue"
-
-// with GStrings too
-def g = "${'green'}" as Color
------------------------------
-
-[[Groovy18releasenotes-MapssupportisCase]]
-=== Maps support isCase()
-
-Maps now support `isCase()`, so you can use maps in your switch/case
-statements, for instance:
-
-[source,groovy]
-----------------------------------------------
-def m = [a: 1, b: 2]
-def val = 'a'
-
-switch (val) {
-    case m: "key in map"; break
-    // equivalent to // case { val in m }: ...
-    default: "not in map"
-}
-----------------------------------------------
-
-[[Groovy18releasenotes-GrapeGrabImprovements]]
-=== Grape/Grab Improvements
-
-[[Groovy18releasenotes-ShorternotationforGrabResolver]]
-==== Shorter notation for @GrabResolver
-
-When you need to specify a special grab resolver, for when the artifacts
-you need are not stored in Maven central, you could use:
-
-[source,groovy]
-----------------------------------------------------------------------
-@GrabResolver(name = 'restlet.org', root = 'http://maven.restlet.org')
-@Grab('org.restlet:org.restlet:2.0.6')
-import org.restlet.Restlet
-----------------------------------------------------------------------
-
-Groovy 1.8 adds a shorter syntax as well:
-
-[source,groovy]
------------------------------------------
-@GrabResolver('http://maven.restlet.org')
-@Grab('org.restlet:org.restlet:2.0.6')
-import org.restlet.Restlet
------------------------------------------
-
-[[Groovy18releasenotes-CompactformforoptionalGrabattributes]]
-==== Compact form for optional Grab attributes
-
-The `@Grab` annotation has numerous options. For example, to download
-the Apache commons-io library (where you wanted to set the `transitive`
-and `force` attributes - not strictly needed for this example but see
-the Grab or Ivy documentation for details on what those attributes do)
-you could use a grab statement similar to below:
-
-[source,groovy]
----------------------------------------------------------------------------------------------
-@Grab(group='commons-io', module='commons-io', version='2.0.1', transitive=false, force=true)
----------------------------------------------------------------------------------------------
-
-The compact form for grab which allows the artifact information to be
-represented as a string now supports specifying additional attributes.
-As an example, the following script will download the commons-io jar and
-the corresponding javadoc jar before using one of the commons-io
-methods.
-
-[source,groovy]
-----------------------------------------------------------------
-@Grab('commons-io:commons-io:2.0.1;transitive=false;force=true')
-@Grab('commons-io:commons-io:2.0.1;classifier=javadoc')
-import static org.apache.commons.io.FileSystemUtils.*
-assert freeSpaceKb() > 0
-----------------------------------------------------------------
-
-[[Groovy18releasenotes-Sqlimprovements]]
-=== Sql improvements
-
-The `eachRow` and `rows` methods in the `groovy.sql.Sql` class now
-support paging. Here\u2019s an example:
-
-[source,groovy]
----------------------------------------------------
-sql.eachRow('select * from PROJECT', 2, 2) { row ->
-  println "${row.name.padRight(10)} ($row.url)"
-}
----------------------------------------------------
-
-Which will start at the second row and return a maximum of 2 rows.
-Here\u2019s an example result from a database containing numerous projects
-with their URLs:
-
-----------------------------------------
-Grails     (http://grails.org)
-Griffon    (http://griffon-framework.org)
-----------------------------------------
-
-[[Groovy18releasenotes-StoringASTnodemetadata]]
-=== Storing AST node metadata
-
-When developing AST transformations, and particularly when using a
-visitor to navigate the AST nodes, it is sometimes tricky to keep track
-of information as you visit the tree, or if a combination of transforms
-need to be sharing some context. The `ASTNode` base class features 4
-methods to store node metadata:
-
-* `public Object getNodeMetaData(Object key)`
-* `public void copyNodeMetaData(ASTNode other)`
-* `public void setNodeMetaData(Object key, Object value)`
-* `public void removeNodeMetaData(Object key)`
-
-[[Groovy18releasenotes-AbilitytocustomizetheGroovyDoctemplates]]
-=== Ability to customize the GroovyDoc templates
-
-GroovyDoc uses hard-coded templates to create the JavaDoc for your
-Groovy classes. Three templates are used: top-level templates, a
-package-level template, a class template. If you want to customize these
-templates, you can subclass the `Groovydoc` Ant task and override the
-`getDocTemplates()`, `getPackageTemplates()`, and `getClassTemplates()`
-methods pointing at your own templates. Then you can use your custom
-GroovyDoc Ant task in lieu of Groovy\u2019s original one.