|
|
Groovy 1.8 release notesCommand chains for nicer Domain-Specific LanguagesThanks 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 language closer to 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 parenthesis-free method calls, requiring neither parentheses around arguments, nor dots between the chained calls. The general idea is that a call like It is also possible to use methods in the chain which take no arguments, but in that case, the parentheses are needed: 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: 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 further examples of "command chains" on the Groovy Web Console but to illustrate creating such a DSL, we will show one example - first using maps and Closures: Or if you prefer Japanese and a metaprogramming style (see here for more details): Performance improvementsGroovy'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:
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. GPars bundled within the Groovy distributionThe 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 your concurrent, asynchronous and parallel needs. To learn more about GPars, head over to the GPars website, or read the detailed online user guide. Closure enhancementsClosures 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 part of what gives Groovy its functional flavor. Closure annotation parametersIn 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. Closure annotation parameters open up some interesting possibilities for framework authors! And for instance, this is the approach taken by the GContracts project, which brings the "Design by Contract" paradigm to Groovy. Closure functional flavorsClosure compositionIf 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: To see more examples of closure composition and reverse composition, please have a look at our test case. Closure trampolineWhen 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 the new trampoline capability. Closures are wrapped in a Here's an example of the use of Closure memoizationAnother improvement to closures is the ability to 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:
Let's illustrate that: Currying improvementsCurrying improvements have also been backported to 1.7, but it's worth outlining there 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: Native JSON supportWith 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. JSON parserA 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: If you want to see some more examples of the usage of the JSON parser, you can have a look at the JsonSlurper tests in our code base. JSON builderParsing 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: Will create the JSON output: You can find some more usages of the JSON builder in our JsonBuilder tests. Pretty printing JSON contentWhen given a JSON data sturcture, 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: Which would result in the following pretty-printed output: New AST Transformations@LogYou can annotate your classes with the @Log transformation to automatically inject a logger in your Groovy classes, under the
Here's a sample usage of the @Log transformation: You can change the name of the logger by specifying a different name, for instance with Another particularity of these logger AST transformations is that they take care of wrapping and safe-guarding logger calls with the usual @FieldWhen 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 More concretely, you'll be able to do as follows: @PackageScope enhancementsThe @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 @AutoCloneThe
See the Javadoc for @AutoExternalizableThe Which will create a class of the following form: Controlling the execution of your codeWhen 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 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 Cédric Champeau, our most recent Groovy committer, who implemented those features, has a very nice blog post covering those code interruption transformations. @ThreadInterruptYou 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: You can specify a @TimedInterruptWith In addition to the previous annotation parameters we mentioned for @ConditionalInterruptAn example of You can imagine defining any kind of condition: on counters, on resource availability, on resource usage, and more. @ToStringProvides your classes with a default And here's another example using a few more options: @EqualsAndHashCodeProvides your classes with @TupleConstructorProvides a tuple (ordered) constructor. For POGOs (plain old Groovy objects), this will be in addition to Groovy's default "named-arg" constructor. @CanonicalAllows you to combine By default, You will find a great write-up on @Canonical, @ToString, @EqualsAndHashCode and @TupleConstructor on John Prystash weblog. @InheritConstructorsSometimes, 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: Simply use the @InheritConstructors transformation which takes care of overriding the base constructors for you: @WithReadLock and @WithWriteLockThose two transformations, combined together, simplify the usage of More concretely, with an example, the following: Will generate code as follows: Alignments with JDK 7Groovy 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. Diamond operatorJava 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: You can "omit" the parameterized types and just use the pointy brackets, which now look like a diamond: New DGM methods
MiscellaneousSlashy stringsSlashy strings are now multi-line: This is particularly useful for multi-line regexs when using the regex free-spacing comment style (though you would still need to escape slashes): Dollar slashy stringsA 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: 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. XML fragments with backslashes: 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: Triple quote (""") GString requires extra escaping. Illegal for a normal slashy string - now ugly workarounds are not needed. Or multi-line regexs when using the regex free-spacing comment style (particularly ones which contain slashes): So, you can cut and paste most PERL regex examples without further escaping. Or Strings which are themselves Groovy code fragments containing slashes: Again, you can cut and paste many slashy string Groovy examples and have them in dollar slashy strings without further escaping. Compilation customizersThe compilation of Groovy code can be configured through the
For example, if you want to apply the @Log transformation to all the classes and scripts, you could do: 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: When you want to evaluate Math expressions, you don't need anymore to use the (G)String to Enum coercionGiven a String or a GString, you can coerce it to Enum values bearing the same name, as the sample below presents: Maps support isCase()Maps now support Shorter notation for @GrabResolverWhen you need to specify a special grab resolver, for when the artifacts you need are not stored in Maven central, you could use: Groovy 1.8 adds a shorter syntax as well: Storing AST node metadataWhen 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
Ability to customize the GroovyDoc templatesGroovyDoc 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 Support for begin() / end() methods when processing files line by line with the groovy commandA feature found in other scripting languages like Perl or Awk is to be able to have a begin / end method when processing a file line by line. The groovy command supports this mode of operation, but didn't support the begin / end methods. (this feature is actually going to be available in 1.7.11 and 1.8.1, but time ran short for inclusion in the 1.8 final release) More concretely, if you have a text file named dummy.txt, and you want to count the number of lines it contains, you could do this on the command-line: |
Labels