| 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’t 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’s 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.を = |
| Object.metaClass.の = { clos -> clos(delegate) } |
| |
| まず = { it } |
| 表示する = { println it } |
| 平方根 = { Math.sqrt(it) } |
| |
| まず 100 の 平方根 を 表示する // 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’ll 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’ll keep it simple with Maps and Closures. We’ll 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’s 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’t 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’s 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’re going further and let you use closures |
| as annotation parameters – 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’re 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’s 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’s 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 – 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’s 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’s worth outlining here for reference. Currying used |
| to be done only from left to right, but it’s 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’s 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’s 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"]}}''') |
| -------------------------------------------------------------------------------------------------------------------- |
| |
| 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’s 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’s 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’ining 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’ll 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’s 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’s 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’t |
| 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’t |
| 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’t 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’ 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’s 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’ 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’s 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’s `@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’s 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’s 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’s 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’s 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’s 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’s 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’t 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’t 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’t 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’s 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’s 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’s original one. |