| == Overview of Groovy 1.6 |
| |
| As we shall see in this article, the main highlights of this Groovy 1.6 |
| release are: |
| |
| * *Greater compile-time and runtime performance improvements* |
| * Multiple assignments |
| * Optional return in `if`/`else` and `try`/`catch` blocks |
| * Java 5 annotation definition |
| * *AST transformations* and all the provided transformation annotations |
| like `@Singleton`, `@Lazy`, `@Immutable`, `@Delegate` and friends |
| * The Grape module and dependency system and its `@Grab` transformation |
| * Various Swing builder improvements, thanks to the Swing |
| / link:http://griffon-framework.org/[Griffon] team, as well as several Swing |
| console improvements |
| * The integration of *JMX builder* |
| * Various *metaprogramming improvements*, like the EMC DSL, per-instance |
| metaclasses even for POJOs, and runtime mixins |
| * *JSR-223* scripting engine built-in |
| * Out-of-the-box *OSGi readiness* |
| |
| All those improvements and new features serve one goal: *helping |
| developers be more productive and more agile*, by: |
| |
| * Focusing more on the task at hand than on boiler-plate technical code |
| * Leveraging existing Enterprise APIs rather than reinventing the wheel |
| * Improving the overall performance and quality of the language |
| * Enabling developers to customize the language at will to derive their |
| own Domain-Specific Languages |
| |
| But beyond all these important aspects, *Groovy is not just a language, |
| it's a whole ecosystem*. |
| |
| The improvements in Groovy's generated bytecode information helps |
| capable tools coverage |
| like link:http://cobertura.github.io/cobertura/[Cobertura] and |
| its Groovy support, or pave the way for new utilities |
| like link:http://codenarc.sourceforge.net/[CodeNarc] for static code analysis |
| for Groovy. |
| |
| The malleability of the syntax of the language and its metaprogramming |
| capabilities give birth to advanced testing tools such as |
| the link:http://easyb.org/[Easyb] Behavior-Driven-Development project, |
| the link:http://code.google.com/p/gmock/[GMock] mocking library or |
| the link:http://code.google.com/p/spock/[Spock] testing and specification |
| framework. |
| |
| Again, Groovy's flexibility and expressiveness and its scripting |
| capabilities open the doors to advanced build scripting or |
| infrastructure systems for your continuous integration practices and |
| project build solutions, such |
| as link:https://gant.github.io/[Gant] and link:http://www.gradle.org/[Gradle]. |
| |
| At the tooling level, Groovy also progresses, for instance with |
| its `groovydoc` Ant task to let you generate proper JavaDoc covering, |
| documenting and interlinking both your Groovy and Java source files for |
| your Groovy/Java mixed projects. |
| |
| And at the same time, IDE makers improve their support for Groovy, by |
| giving users powerful weapons such as cross-language code refactoring, |
| profound understanding of dynamic language idioms, code completion, and |
| more, to make developers productive when using Groovy in their projects. |
| |
| Now, armed with this knowledge of the Groovy world, it's time to dive |
| into the novelties of Groovy 1.6! |
| |
| [[Groovy16releasenotes-Performanceimprovements]] |
| == Performance improvements |
| |
| A lot of care has been taken to improve both the compile-time and |
| runtime performance of Groovy, compared to previous releases. |
| |
| The *compiler is 3 to 5 times faster* than in previous releases. This |
| improvement has also been back-ported in the 1.5.x branch, so that both |
| the old maintenance branch and the current stable branch benefit from |
| this work. Thanks to class lookup caches, the bigger the project, the |
| faster the compilation will be. |
| |
| However, the most noticeable changes will be in the general runtime |
| performance improvements of Groovy. We used several benchmarks from |
| the link:https://salsa.debian.org/benchmarksgame-team/archive-alioth-benchmarksgame/tree/master/contributed-source-code/shootout[Great Language Shootout] to |
| measure our progress. On those we selected, compared to the old Groovy |
| 1.5.x line, the*performance improvements ranged from 150% to 460%*. |
| Micro-benchmarks obviously rarely reflect the kind of code you have in |
| your own projects, but the overall performance of your projects should |
| improve significantly. |
| |
| [[Groovy16releasenotes-Multipleassignments]] |
| == Multiple assignments |
| |
| In Groovy 1.6, there is only one syntax addition for being able to |
| define and assign several variables at once: |
| |
| [source,groovy] |
| ------------------- |
| def (a, b) = [1, 2] |
| |
| assert a == 1 |
| assert b == 2 |
| ------------------- |
| |
| A more meaningful example may be methods returning longitude and latitude |
| coordinates. If these coordinates are represented as a list of two |
| elements, you can easily get back to each element as follows: |
| |
| [source,groovy] |
| --------------------------------------------------------------------- |
| def geocode(String location) { |
| // implementation returns [48.824068, 2.531733] for Paris, France |
| } |
| |
| def (lat, long) = geocode("Paris, France") |
| |
| assert lat == 48.824068 |
| assert long == 2.531733 |
| --------------------------------------------------------------------- |
| |
| And you can also define the types of the variables in one shot as |
| follows: |
| |
| [source,groovy] |
| ------------------------------------- |
| def (int i, String s) = [1, 'Groovy'] |
| |
| assert i == 1 |
| assert s == 'Groovy' |
| ------------------------------------- |
| |
| For the assignment (with prior definition of the variables), just omit |
| the `def` keyword: |
| |
| [source,groovy] |
| ------------------------------------------------------ |
| def firstname, lastname |
| |
| (firstname, lastname) = "Guillaume Laforge".tokenize() |
| |
| assert firstname == "Guillaume" |
| assert lastname == "Laforge" |
| ------------------------------------------------------ |
| |
| If the list on the right-hand side contains more elements than the |
| number of variables on the left-hand side, only the first elements will |
| be assigned in order into the variables. Also, when there are less |
| elements than variables, the extra variables will be assigned null. |
| |
| So for the case with more variables than list elements, here, `c` will |
| be `null`: |
| |
| [source,groovy] |
| ------------------------ |
| def elements = [1, 2] |
| def (a, b, c) = elements |
| |
| assert a == 1 |
| assert b == 2 |
| assert c == null |
| ------------------------ |
| |
| Whereas in the case where there are more list elements than variables, |
| we'll get the following expectations: |
| |
| [source,groovy] |
| --------------------------- |
| def elements = [1, 2, 3, 4] |
| def (a, b, c) = elements |
| |
| assert a == 1 |
| assert b == 2 |
| assert c == 3 |
| --------------------------- |
| |
| For the curious minds, supporting multiple assignments also means we can |
| do the standard school swap case in one line: |
| |
| [source,groovy] |
| ----------------------------- |
| // given those two variables |
| def a = 1, b = 2 |
| |
| // swap variables with a list |
| (a, b) = [b, a] |
| |
| assert a == 2 |
| assert b == 1 |
| ----------------------------- |
| |
| [[Groovy16releasenotes-Annotationdefinition]] |
| == Annotation definition |
| |
| Actually, when I said that multiple assignments were the sole syntax |
| addition, it's not entirely true. Groovy supported the syntax for |
| annotation definition even in Groovy 1.5, but we had not implemented the |
| feature completely. Fortunately, this is now fixed, and it wraps up all |
| the Java 5 features supported by Groovy, such as *static |
| imports*, *generics*, *annotations*, and *enums*, making Groovy |
| the *sole alternative dynamic language for the JVM supporting all those |
| Java 5 features*, which is critical for a seamless Java integration |
| story, and for the usage in Enterprise frameworks relying on |
| annotations, generics and more, like JPA, EJB3, Spring, TestNG, etc. |
| |
| [[Groovy16releasenotes-Optionalreturnforifelseandtrycatchfinallyblocks]] |
| == Optional return for if/else and try/catch/finally blocks |
| |
| It is now possible for `if/else` and `try/catch/finally` blocks to |
| return a value when they are the last expression in a method or a |
| closure. No need to explicitly use the `return` keyword inside these |
| constructs, as long as they are the latest expression in the block of |
| code. |
| |
| As an example, the following method will return `1`, although |
| the `return` keyword was omitted. |
| |
| [source,groovy] |
| ---------------------- |
| def method() { |
| if (true) 1 else 0 |
| } |
| |
| assert method() == 1 |
| ---------------------- |
| |
| For `try/catch/finally` blocks, the last expression evaluated is the one |
| being returned. If an exception is thrown in the `try` block, the last |
| expression in the `catch` block is returned instead. Note |
| that `finally` blocks don't return any value. |
| |
| [source,groovy] |
| -------------------------------------------- |
| def method(bool) { |
| try { |
| if (bool) throw new Exception("foo") |
| 1 |
| } catch(e) { |
| 2 |
| } finally { |
| 3 |
| } |
| } |
| |
| assert method(false) == 1 |
| assert method(true) == 2 |
| -------------------------------------------- |
| |
| [[Groovy16releasenotes-ASTTransformations]] |
| == AST Transformations |
| |
| Although at times, it may sound like a good idea to extend the syntax of |
| Groovy to implement new features (like this is the case for instance for |
| multiple assignments), most of the time, we can't just add a new keyword |
| to the grammar, or create some new syntax construct to represent a new |
| concept. However, with the idea of AST (Abstract Syntax Tree) |
| Transformations, we are able to tackle new and innovative ideas without |
| necessary grammar changes. |
| |
| When the Groovy compiler compiles Groovy scripts and classes, at some |
| point in the process, the source code will end up being represented in |
| memory in the form of a Concrete Syntax Tree, then transformed into an |
| Abstract Syntax Tree. The purpose of AST Transformations is to let |
| developers hook into the compilation process to be able to modify the |
| AST before it is turned into bytecode that will be run by the JVM. |
| |
| *AST Transformations provides Groovy with improved compile-time |
| metaprogramming capabilities* allowing powerful flexibility at the |
| language level, without a runtime performance penalty. |
| |
| There are two kinds of transformations: global and local |
| transformations. |
| |
| * Global transformations are applied to by the compiler on the code |
| being compiled, wherever the transformation apply. A JAR added to the |
| classpath of the compiler should contain a service locator file |
| at `META-INF/services/org.codehaus.groovy.transform.ASTTransformation` with |
| a line with the name of the transformation class. The transformation |
| class must have a no-args constructor and implement |
| the `org.codehaus.groovy.transform.ASTTransformation`interface. It will |
| be run against every source in the compilation, so be sure to not create |
| transformations which scan all the AST in an expansive and |
| time-consuming manner, to keep the compiler fast. |
| * Local transformations are transformations applied locally by |
| annotating code elements you want to transform. For this, we reuse the |
| annotation notation, and those annotations should |
| implement `org.codehaus.groovy.transform.ASTTransformation`. The |
| compiler will discover them and apply the transformation on these code |
| elements. |
| |
| Groovy 1.6 provides several local transformation annotations, in the |
| Groovy Swing Builder for data binding (`@Bindable` and `@Vetoable`), in |
| the Grape module system for adding script library dependencies |
| (`@Grab`), or as general language features without requiring any syntax |
| change to support them |
| (`@Singleton`, `@Immutable`, `@Delegate`, `@Lazy`, `@Newify`, `@Category`, `@Mixin` and `@PackageScope`). |
| Let's have a look at some of these transformations |
| (`@Bindable` and `@Vetoable` will be covered in the section related to |
| the Swing enhancements, and `@Grab` in the section about Grape). |
| |
| [[Groovy16releasenotes-Singleton]] |
| === @Singleton |
| |
| Whether the singleton is pattern or an anti-pattern, there are still |
| some cases where we need to create singletons. We're used to create a |
| private constructor, a `getInstance()` method for a static field or even |
| an initialized `public static final` field. So instead of writing code |
| like this in Java: |
| |
| [source,groovy] |
| --------------------------------------------- |
| public class T { |
| public static final T instance = new T(); |
| private T() {} |
| } |
| --------------------------------------------- |
| |
| You just need to annotate your type with the `@Singleton` annotation: |
| |
| [source,groovy] |
| --------------------- |
| @Singleton class T {} |
| --------------------- |
| |
| The singleton instance can then simply be accessed |
| with `T.instance` (direct public field access). |
| |
| You can also have the lazy loading approach with an additional |
| annotation parameter: |
| |
| [source,groovy] |
| ---------------------------------- |
| @Singleton(lazy = true) class T {} |
| ---------------------------------- |
| |
| Would become more or less equivalent to this Groovy class: |
| |
| [source,groovy] |
| --------------------------------------- |
| class T { |
| private static volatile T instance |
| private T() {} |
| static T getInstance () { |
| if (instance) { |
| instance |
| } else { |
| synchronized(T) { |
| if (instance) { |
| instance |
| } else { |
| instance = new T () |
| } |
| } |
| } |
| } |
| } |
| --------------------------------------- |
| |
| Lazy or not, once again, to access the instance, simply |
| do `T.instance` (property access, shortcut for `T.getInstance()`). |
| |
| [[Groovy16releasenotes-Immutable]] |
| === @Immutable |
| |
| Immutable objects are ones which don't change after initial creation. |
| Such objects are frequently desirable because they are simple and can be |
| safely shared even in multi-threading contexts. This makes them great |
| for functional and concurrent scenarios. The rules for creating such |
| objects are well-known: |
| |
| * No mutators (methods that modify internal state) |
| * Class must be final |
| * Fields must be private and final |
| * Defensive copying of mutable components |
| * `equals()`, `hashCode()` and `toString()` must be implemented in terms |
| of the fields if you want to compare your objects or use them as keys in |
| e.g. maps |
| |
| Instead of writing a very long Java or Groovy class mimicking this |
| immutability behavior, Groovy lets you just write an immutable class as |
| follow: |
| |
| [source,groovy] |
| ------------------------------------------------------------------ |
| @Immutable final class Coordinates { |
| Double latitude, longitude |
| } |
| |
| def c1 = new Coordinates(latitude: 48.824068, longitude: 2.531733) |
| def c2 = new Coordinates(48.824068, 2.531733) |
| |
| assert c1 == c2 |
| ------------------------------------------------------------------ |
| |
| All the boiler-plate code is generated at compile-time for you! The |
| example shows that to instantiate such immutable coordinates, you can |
| use one of the two constructors created by the transformation, one |
| taking a map whose keys are the properties to set to the values |
| associated with those keys, and the other taking the values of the |
| properties as parameters. The `assert` also shows that `equals()` was |
| implemented and allows us to properly compare such immutable objects. |
| |
| You can have a look at |
| the link:http://docs.groovy-lang.org/latest/html/gapi/groovy/transform/Immutable.html[details of the implementation] of this transformation. For the record, the Groovy |
| example above using the`@Immutable` transformation is over 50 lines of |
| equivalent Java code. |
| |
| [[Groovy16releasenotes-Lazy]] |
| === @Lazy |
| |
| Another transformation is `@Lazy`. Sometimes, you want to handle the |
| initialization of a field of your class lazily, so that its value is |
| computed only on first use, often because it may be time-consuming or |
| memory-expensive to create. The usual approach is to customize the |
| getter of said field, so that it takes care of the initialization when |
| the getter is called the first time. But in Groovy 1.6, you can now use |
| the `@Lazy` annotation for that purpose: |
| |
| [source,groovy] |
| --------------------------------------- |
| class Person { |
| @Lazy pets = ['Cat', 'Dog', 'Bird'] |
| } |
| |
| def p = new Person() |
| assert !(p.dump().contains('Cat')) |
| |
| assert p.pets.size() == 3 |
| assert p.dump().contains('Cat') |
| --------------------------------------- |
| |
| In the case of complex computation for initializing the field, you may |
| need to call some method for doing the work, instead of a value like our |
| pets list. This is then possible to have the lazy evaluation being done |
| by a closure call, as the following example shows: |
| |
| [source,groovy] |
| ---------------------------------------------------------- |
| class Person { |
| @Lazy List pets = { /* complex computation here */ }() |
| } |
| ---------------------------------------------------------- |
| |
| There is also an option for leveraging Soft references for garbage |
| collection friendliness for expensive data structures that may be |
| contained by such lazy fields: |
| |
| [source,groovy] |
| --------------------------------------------------------- |
| class Person { |
| @Lazy(soft = true) List pets = ['Cat', 'Dog', 'Bird'] |
| } |
| |
| def p = new Person() |
| assert p.pets.contains('Cat') |
| --------------------------------------------------------- |
| |
| The internal field created by the compiler for `pets` will actually be a |
| Soft reference, but accessing `p.pets` directly will return the value |
| (ie. the list of pets) held by that reference, making the use of the |
| soft reference transparent to the user of that class. |
| |
| [[Groovy16releasenotes-Delegate]] |
| === @Delegate |
| |
| Java doesn't provide any built-in delegation mechanism, and so far |
| Groovy didn't either. But with the `@Delegate` transformation, a class |
| field or property can be annotated and become an object to which method |
| calls are delegated. In the following example, an `Event` class has a |
| date delegate, and the compiler will delegate all of `Date`'s methods |
| invoked on the `Event` class to the `Date` delegate. As shown in the |
| latest `assert`, the `Event` class has got a `before(Date)` method, and |
| all of `Date`'s methods. |
| |
| [source,groovy] |
| -------------------------------------------------------------- |
| import java.text.SimpleDateFormat |
| |
| class Event { |
| @Delegate Date when |
| String title, url |
| } |
| |
| def df = new SimpleDateFormat("yyyy/MM/dd") |
| |
| def gr8conf = new Event(title: "GR8 Conference", |
| url: "http://www.gr8conf.org", |
| when: df.parse("2009/05/18")) |
| def javaOne = new Event(title: "JavaOne", |
| url: "http://java.sun.com/javaone/", |
| when: df.parse("2009/06/02")) |
| |
| assert gr8conf.before(javaOne.when) |
| -------------------------------------------------------------- |
| |
| The Groovy compiler adds all of `Date`'s methods to the `Event` class, |
| and those methods simply delegate the call to the `Date` field. If the |
| delegate is not a final class, it is even possible to make |
| the `Event` class a subclass of `Date` simply by extending `Date`, as |
| shown below. No need to implement the delegation ourselves by adding |
| each and every `Date` methods to our `Event` class, since the compiler |
| is friendly-enough with us to do the job itself. |
| |
| [source,groovy] |
| -------------------------- |
| class Event extends Date { |
| @Delegate Date when |
| String title, url |
| } |
| -------------------------- |
| |
| In the case you are delegating to an interface, however, you don't even |
| need to explicitly say you implement the interface of the delegate. |
| The `@Delegate` transformation will take care of this and implement that |
| interface. So the instances of your class will automatically |
| be `instanceof` the delegate's interface. |
| |
| [source,groovy] |
| ----------------------------------------------------- |
| import java.util.concurrent.locks.* |
| |
| class LockableList { |
| @Delegate private List list = [] |
| @Delegate private Lock lock = new ReentrantLock() |
| } |
| |
| def list = new LockableList() |
| |
| list.lock() |
| try { |
| list << 'Groovy' |
| list << 'Grails' |
| list << 'Griffon' |
| } finally { |
| list.unlock() |
| } |
| |
| assert list.size() == 3 |
| assert list instanceof Lock |
| assert list instanceof List |
| ----------------------------------------------------- |
| |
| In this example, our `LockableList` is now a composite of a list and a |
| lock and is `instanceof` of `List` and `Lock`. However, if you didn't |
| intend your class to be implementing these interfaces, you would still |
| be able to do so by specifying a parameter on the annotation: |
| |
| [source,groovy] |
| ---------------------------------------------------- |
| @Delegate(interfaces = false) private List list = [] |
| ---------------------------------------------------- |
| |
| [[Groovy16releasenotes-Newify]] |
| === @Newify |
| |
| The `@Newify` transformation proposes two new ways of instantiating |
| classes. The first one is providing Ruby like approach to creating |
| instances with a `new()` class method: |
| |
| [source,groovy] |
| -------------------------------- |
| @Newify rubyLikeNew() { |
| assert Integer.new(42) == 42 |
| } |
| |
| rubyLikeNew() |
| -------------------------------- |
| |
| But it is also possible to follow the Python approach with omitting |
| the `new` keyword. Imagine the following tree creation: |
| |
| [source,groovy] |
| ----------------------------------------------------------------- |
| class Tree { |
| def elements |
| Tree(Object... elements) { this.elements = elements as List } |
| } |
| |
| class Leaf { |
| def value |
| Leaf(value) { this.value = value } |
| } |
| |
| def buildTree() { |
| new Tree(new Tree(new Leaf(1), new Leaf(2)), new Leaf(3)) |
| } |
| |
| buildTree() |
| ----------------------------------------------------------------- |
| |
| The creation of the tree is not very readable because of all |
| those `new` keywords spread across the line. The Ruby approach wouldn't |
| be more readable, since a `new()` method call for creating each element |
| is needed. But by using `@Newify`, we can improve our tree building |
| slightly to make it easier on the eye: |
| |
| [source,groovy] |
| ----------------------------------------- |
| @Newify([Tree, Leaf]) buildTree() { |
| Tree(Tree(Leaf(1), Leaf(2)), Leaf(3)) |
| } |
| ----------------------------------------- |
| |
| You'll also notice that we just allowed `Tree` and `Leaf` to |
| be _newified_. By default, under the scope which is annotated, all |
| instantiations are_newified_, but you can limit the reach by specifying |
| the classes you're interested in. Also, note that for our example, |
| perhaps a Groovy builder may have been more appropriate, since its |
| purpose is to indeed create any kind of hierarchical / tree structure. |
| |
| If we take another look at our coordinates example from a few sections |
| earlier, using both `@Immutable` and `@Newify` can be interesting for |
| creating a path with a concise but type-safe manner: |
| |
| [source,groovy] |
| ----------------------------------------- |
| @Immutable final class Coordinates { |
| Double latitude, longitude |
| } |
| |
| @Immutable final class Path { |
| Coordinates[] coordinates |
| } |
| |
| @Newify([Coordinates, Path]) |
| def build() { |
| Path( |
| Coordinates(48.824068, 2.531733), |
| Coordinates(48.857840, 2.347212), |
| Coordinates(48.858429, 2.342622) |
| ) |
| } |
| |
| assert build().coordinates.size() == 3 |
| ----------------------------------------- |
| |
| A closing remark here: since a `Path(Coordinates[] coordinates)` was |
| generated, we can use that constructor in a _varargs way_ in Groovy, |
| just as if it had been defined as `Path(Coordinates... coordinates)`. |
| |
| [[Groovy16releasenotes-CategoryandMixin]] |
| === @Category and @Mixin |
| |
| If you've been using Groovy for a while, you're certainly familiar with |
| the concept of Categories. It's a mechanism to extend existing types |
| (even final classes from the JDK or third-party libraries), to add new |
| methods to them. This is also a technique which can be used when writing |
| Domain-Specific Languages. Let's consider the example below: |
| |
| [source,groovy] |
| -------------------------------------------- |
| final class Distance { |
| def number |
| String toString() { "${number}m" } |
| } |
| |
| class NumberCategory { |
| static Distance getMeters(Number self) { |
| new Distance(number: self) |
| } |
| } |
| |
| use(NumberCategory) { |
| def dist = 300.meters |
| |
| assert dist instanceof Distance |
| assert dist.toString() == "300m" |
| } |
| -------------------------------------------- |
| |
| We have a simplistic and fictive `Distance` class which may have been |
| provided by a third-party, who had the bad idea of making the |
| class`final` so that nobody could ever extend it in any way. But thanks |
| to a Groovy Category, we are able to decorate the `Distance` type with |
| additional methods. Here, we're going to add a `getMeters()` method to |
| numbers, by actually decorating the `Number` type. By adding a getter to |
| a number, you're able to reference it using the nice property syntax of |
| Groovy. So instead of writing `300.getMeters()`, you're able to |
| write `300.meters`. |
| |
| The downside of this category system and notation is that to add |
| instance methods to other types, you have to create `static` methods, |
| and furthermore, there's a first argument which represents the instance |
| of the type we're working on. The other arguments are the normal |
| arguments the method will take as parameters. So it may be a bit less |
| intuitive than a normal method definition we would have added |
| to `Distance`, should we have had access to its source code for |
| enhancing it. Here comes the `@Category` annotation, which transforms a |
| class with instance methods into a Groovy category: |
| |
| [source,groovy] |
| ---------------------------------- |
| @Category(Number) |
| class NumberCategory { |
| Distance getMeters() { |
| new Distance(number: this) |
| } |
| } |
| ---------------------------------- |
| |
| No need for declaring the methods `static`, and the `this` you use here |
| is actually the number on which the category will apply, it's not the |
| real `this` of the category instance should we create one. Then to use |
| the category, you can continue to use the `use(Category) {}`construct. |
| What you'll notice however is that these kind of categories only apply |
| to one single type at a time, unlike classical categories which can be |
| applied to any number of types. |
| |
| Now, pair `@Category` extensions to the `@Mixin` transformation, and you |
| can mix in various behavior in a class, with an approach similar to |
| multiple inheritance: |
| |
| [source,groovy] |
| ------------------------------------------------- |
| @Category(Vehicle) class FlyingAbility { |
| def fly() { "I'm the ${name} and I fly!" } |
| } |
| |
| @Category(Vehicle) class DivingAbility { |
| def dive() { "I'm the ${name} and I dive!" } |
| } |
| |
| interface Vehicle { |
| String getName() |
| } |
| |
| @Mixin(DivingAbility) |
| class Submarine implements Vehicle { |
| String getName() { "Yellow Submarine" } |
| } |
| |
| @Mixin(FlyingAbility) |
| class Plane implements Vehicle { |
| String getName() { "Concorde" } |
| } |
| |
| @Mixin([DivingAbility, FlyingAbility]) |
| class JamesBondVehicle implements Vehicle { |
| String getName() { "James Bond's vehicle" } |
| } |
| |
| assert new Plane().fly() == |
| "I'm the Concorde and I fly!" |
| assert new Submarine().dive() == |
| "I'm the Yellow Submarine and I dive!" |
| |
| assert new JamesBondVehicle().fly() == |
| "I'm the James Bond's vehicle and I fly!" |
| assert new JamesBondVehicle().dive() == |
| "I'm the James Bond's vehicle and I dive!" |
| ------------------------------------------------- |
| |
| You don't inherit from various interfaces and inject the same behavior |
| in each subclass, instead you mixin the categories into your class. |
| Here, our marvelous James Bond vehicle gets the flying and diving |
| capabilities through mixins. |
| |
| An important point to make here is that unlike `@Delegate` which |
| can _inject_ interfaces into the class in which the delegate is |
| declared,`@Mixin` just does runtime mixing — as we shall see in the |
| metaprogramming enhancements further down in this article. |
| |
| [[Groovy16releasenotes-PackageScope]] |
| === @PackageScope |
| |
| Groovy's convention for properties is that any _field_ without any |
| visibility modifier is exposed as a property, with a getter and a setter |
| transparently generated for you. For instance, this `Person` class |
| exposes a getter `getName()` and a setter `setName()` for a |
| private `name` field: |
| |
| [source,groovy] |
| --------------- |
| class Person { |
| String name |
| } |
| --------------- |
| |
| Which is equivalent to this Java class: |
| |
| [source,groovy] |
| --------------------------------------------------- |
| public class Person { |
| private String name; |
| public String getName() { return name; } |
| public void setName(name) { this.name = name; } |
| } |
| --------------------------------------------------- |
| |
| That said, this approach has one drawback in that you don't have the |
| possibility to define a field with package-scope visibility. To be able |
| to expose a field with package-scope visibility, you can now annotate |
| your field with the `@PackageScope` annotation. |
| |
| [[Groovy16releasenotes-GrapetheGroovyAdaptableAdvancedPackagingEngine]] |
| == Grape, the Groovy Adaptable / Advanced Packaging Engine |
| |
| To continue our overview of the AST transformations, we'll now learn |
| more about Grape, a mechanism to add and leverage dependencies in your |
| Groovy scripts. Groovy scripts can require certain libraries: by |
| explicitly saying so in your script with the *@Grab* transformation or |
| with the *Grape.grab()* method call, the runtime will find the needed |
| JARs for you. With Grape, you can easily distribute scripts without |
| their dependencies, and have them downloaded on first use of your script |
| and cached. Under the hood, Grape uses Ivy and Maven repositories |
| containing the libraries you may need in your scripts. |
| |
| Imagine you want to get the links of all the PDF documents referenced by |
| the Java 5 documentation. You want to parse the HTML page as if it were |
| an XML-compliant document (which it is not) with the Groovy `XmlParser`, |
| so you can use the TagSoup SAX-compliant parser which transforms HTML |
| into well-formed valid XML. You don't even have to mess up with your |
| classpath when running your script, just_grab_ the TagSoup library |
| through Grape: |
| |
| [source,groovy] |
| ------------------------------------------------------------------------ |
| import org.ccil.cowan.tagsoup.Parser |
| |
| // find the PDF links in the Java 1.5.0 documentation |
| @Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7') |
| def getHtml() { |
| def tagsoupParser = new Parser() |
| def parser = new XmlParser(tagsoupParser) |
| parser.parse("http://java.sun.com/j2se/1.5.0/download-pdf.html") |
| } |
| |
| html.body.'**'.a.@href.grep(~/.*\.pdf/).each{ println it } |
| ------------------------------------------------------------------------ |
| |
| For the pleasure of giving another example: let's use |
| the link:http://eclipse.org/jetty/[Jetty servlet container] to |
| expose link:{DOCS_BASEURL}/html/documentation/template-engines.html[Groovy templates] in |
| a few lines of code: |
| |
| [source,groovy] |
| -------------------------------------------------------------------------------- |
| import org.mortbay.jetty.Server |
| import org.mortbay.jetty.servlet.* |
| import groovy.servlet.* |
| |
| @Grab(group = 'org.mortbay.jetty', module = 'jetty-embedded', version = '6.1.0') |
| def runServer(duration) { |
| def server = new Server(8080) |
| def context = new Context(server, "/", Context.SESSIONS); |
| context.resourceBase = "." |
| context.addServlet(TemplateServlet, "*.gsp") |
| server.start() |
| sleep duration |
| server.stop() |
| } |
| |
| runServer(10000) |
| -------------------------------------------------------------------------------- |
| |
| Grape will download Jetty and its dependencies on first launch of this |
| script, and cache them. We're creating a new Jetty `Server` on port |
| 8080, then expose Groovy's `TemplateServlet` at the root of the context |
| — Groovy comes with its own powerful template engine mechanism. We start |
| the server and let it run for a certain duration. Each time someone will |
| hit +http://localhost:8080/somepage.gsp+, it will display |
| the `somepage.gsp` template to the user — those template pages should be |
| situated in the same directory as this server script. |
| |
| Grape can also be used as a method call instead of as an annotation. You |
| can also install, list, resolve dependencies from the command-line using |
| the `grape` command. For link:../grape.html[more information on Grape], please refer to the documentation. |
| |
| [[Groovy16releasenotes-Swingbuilderimprovements]] |
| == Swing builder improvements |
| |
| To wrap up our overview of AST transformations, let's finish by speaking |
| about two transformations very useful to Swing |
| developers:`@Bindable` and `@Vetoable`. When creating Swing UIs, you're |
| often interested in monitoring the changes of value of certain UI |
| elements. For this purpose, the usual approach is to use |
| JavaBeans `PropertyChangeListener`s to be notified when the value of a |
| class field changes. You then end up writing this very common |
| boiler-plate code in your Java beans: |
| |
| [source,groovy] |
| ------------------------------------------------------------------------ |
| import com.googlecode.openbeans.PropertyChangeSupport; |
| import com.googlecode.openbeans.PropertyChangeListener; |
| |
| public class MyBean { |
| private String prop; |
| |
| PropertyChangeSupport pcs = new PropertyChangeSupport(this); |
| |
| public void addPropertyChangeListener(PropertyChangeListener l) { |
| pcs.add(l); |
| } |
| |
| public void removePropertyChangeListener(PropertyChangeListener l) { |
| pcs.remove(l); |
| } |
| |
| public String getProp() { |
| return prop; |
| } |
| |
| public void setProp(String prop) { |
| pcs.firePropertyChanged("prop", this.prop, this.prop = prop); |
| } |
| |
| } |
| ------------------------------------------------------------------------ |
| |
| Fortunately, with Groovy and the `@Bindable` annotation, this code can |
| be greatly simplified: |
| |
| [source,groovy] |
| ------------------------- |
| class MyBean { |
| @Bindable String prop |
| } |
| ------------------------- |
| |
| Now pair that with Groovy's Swing builder new `bind()` method, define a |
| text field and bind its value to a property of your data model: |
| |
| [source,groovy] |
| -------------------------------------------------------------------- |
| textField text: bind(source: myBeanInstance, sourceProperty: 'prop') |
| -------------------------------------------------------------------- |
| |
| Or even: |
| |
| [source,groovy] |
| -------------------------------------------- |
| textField text: bind { myBeanInstance.prop } |
| -------------------------------------------- |
| |
| The binding also works with simple expressions in the closure, for |
| instance something like this is possible too: |
| |
| [source,groovy] |
| -------------------------------------------- |
| bean location: bind { pos.x + ', ' + pos.y } |
| -------------------------------------------- |
| |
| You may also be interested in having a look |
| at link:{DOCS_BASEURL}/html/api/groovy/util/ObservableMap.html[ObservableMap] and link:{DOCS_BASEURL}/html/api/groovy/util/ObservableList.html[ObservableList], |
| for a similar mechanism on maps and lists. |
| |
| Along with `@Bindable`, there's also a `@Vetoable` transformation for |
| when you need to be able to veto some property change. Let's consider |
| a `Trumpetist` class, where the performer's name is not allowed to |
| contain the letter `z': |
| |
| [source,groovy] |
| --------------------------------------------------------------------------------------- |
| import com.googlecode.openbeans.* |
| import groovy.beans.Vetoable |
| |
| class Trumpetist { |
| @Vetoable String name |
| } |
| |
| def me = new Trumpetist() |
| me.vetoableChange = { PropertyChangeEvent pce -> |
| if (pce.newValue.contains('z')) |
| throw new PropertyVetoException("The letter 'z' is not allowed in a name", pce) |
| } |
| |
| me.name = "Louis Armstrong" |
| |
| try { |
| me.name = "Dizzy Gillespie" |
| assert false: "You should not be able to set a name with letter 'z' in it." |
| } catch (PropertyVetoException pve) { |
| assert true |
| } |
| --------------------------------------------------------------------------------------- |
| |
| Looking at a more thorough Swing builder example with binding: |
| |
| [source,groovy] |
| ---------------------------------------------------------------------------- |
| import groovy.swing.SwingBuilder |
| import groovy.beans.Bindable |
| import static javax.swing.JFrame.EXIT_ON_CLOSE |
| |
| class TextModel { |
| @Bindable String text |
| } |
| |
| def textModel = new TextModel() |
| |
| SwingBuilder.build { |
| frame( title: 'Binding Example (Groovy)', size: [240,100], show: true, |
| locationRelativeTo: null, defaultCloseOperation: EXIT_ON_CLOSE ) { |
| gridLayout cols: 1, rows: 2 |
| textField id: 'textField' |
| bean textModel, text: bind{ textField.text } |
| label text: bind{ textModel.text } |
| } |
| } |
| ---------------------------------------------------------------------------- |
| |
| Running this script shows up the frame below with a text field and a |
| label below, and the label's text is bound on the text field's content. |
| |
| image:https://web.archive.org/web/20160102200635/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-without-visu.png[image] |
| |
| SwingBuilder has evolved so nicely in the past year that the Groovy |
| Swing team decided to launch a new project based on it, and on the |
| Grails foundations: project link:http://griffon-framework.org/[Griffon] was |
| born. Griffon proposes to bring the _Convention over |
| Configuration_ paradigm of Grails, as well as all its project structure, |
| plugin system, gant scripting capabilities, etc. |
| |
| If you are developing Swing rich clients, make sure to have a look |
| at link:http://griffon-framework.org/[Griffon]. |
| |
| [[Groovy16releasenotes-Swingconsoleimprovements]] |
| == Swing console improvements |
| |
| Swinging along the topic of UIs, the Swing console has also evolved: |
| |
| * The console can be run as an Applet (`groovy.ui.ConsoleApplet`). |
| * Beyond syntax highlighting, the editor also supports code indentation. |
| * Drag'n'dropping a Groovy script over the text area will open the file. |
| * You can modify the classpath with which the script in the console is |
| being run, by adding a new JAR or a directory to the classpath as shown |
| in the screenshot below. |
| + |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-add-jar.png[image] |
| |
| * A couple options have been added to the view menu item: for showing |
| the script being run in the output area, and for visualizing the |
| execution results. |
| + |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-options.png[image] |
| |
| * When an exception is thrown in your script, the lines of the |
| stacktrace relative to your script are clickable, for easy navigation to |
| the point where the error occurred. |
| + |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-click-stack.png[image] |
| |
| * Also, when your script contains compilation errors, the error messages are clickable too. |
| + |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-click-comp-error.png[image] |
| |
| Back on the visualization of the results in the script output area, a |
| fun system was added to let you customize how certain results are |
| rendered. When you execute a script returning a map of Jazz musicians, |
| you may see something like this in your console: |
| |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-without-visu.png[image] |
| |
| What you see here is the usual textual representation of a `Map`. But, |
| what if we enabled custom visualization of certain results? The Swing |
| console allows you to do just that. First of all, you have to ensure |
| that the visualization option is |
| ticked: `View -> Visualize Script Results` — for the record, all |
| settings of the Groovy Console are stored and remembered thanks to the |
| Preference API. There are a few result visualizations built-in: if the |
| script returns a `java.awt.Image`, a `javax.swing.Icon`, or |
| a `java.awt.Component` with no parent, the object is displayed instead |
| of its `toString()` representation. Otherwise, everything else is still |
| just represented as text. Now, create the following Groovy script |
| in `~/.groovy/OutputTransforms.groovy`: |
| |
| [source,groovy] |
| --------------------------------------------------------- |
| import javax.swing.* |
| |
| transforms << { result -> |
| if (result instanceof Map) { |
| def table = new JTable( |
| result.collect{ k, v -< |
| [k, v?.inspect()] as Object[] |
| } as Object[][], |
| ['Key', 'Value'] as Object[]) |
| table.preferredViewportSize = table.preferredSize |
| return new JScrollPane(table) |
| } |
| } |
| --------------------------------------------------------- |
| |
| The Groovy Swing console will execute that script on startup, injecting |
| a `transforms` list in the binding of the script, so that you can add |
| your own script results representations. In our case, we transform |
| the `Map` into a nice-looking Swing `JTable`. And we're now able to |
| visualize maps in a friendly and attractive fashion, as the screenshot |
| below shows: |
| |
| image:https://web.archive.org/web/20160102200636/http://www.infoq.com/resource/articles/groovy-1-6/en/resources/sc-with-visu.png[image] |
| |
| The Swing console is obviously not to be confused with a real full-blown |
| IDE, but for daily scripting tasks, the console is a handy tool in your |
| toolbox. |
| |
| [[Groovy16releasenotes-Metaprogrammingenhancements]] |
| == Metaprogramming enhancements |
| |
| What makes Groovy a dynamic language is its Meta-Object Protocol and its |
| concept of metaclasses which represent the runtime behavior of your |
| classes and instances. In Groovy 1.6, we continue improving this dynamic |
| runtime system, bringing several new capabilities into the mix. |
| |
| [[Groovy16releasenotes-PerinstancemetaclassevenforPOJOs]] |
| === Per instance metaclass even for POJOs |
| |
| So far, Groovy POGOs (Plain Old Groovy Objects) could have a |
| per-instance metaclass, but POJOs could only have one metaclass for all |
| instances (ie. a per-class metaclass). This is now not the case anymore, |
| as POJOs can have a per-instance metaclass too. Also, setting the |
| metaclass property to null will restore the default metaclass. |
| |
| [[Groovy16releasenotes-ExpandoMetaClassDSL]] |
| === ExpandoMetaClass DSL |
| |
| Initially developed under the link:http://grails.org/[Grails] umbrella and |
| integrated back into Groovy 1.5, ExpandoMetaClass is a very handy way |
| for changing the runtime behavior of your objects and classes, instead |
| of writing full-blow `MetaClass` classes. Each time, we want to add / |
| change several properties or methods of an existing type, there is too |
| much of a repetition of `Type.metaClass.xxx`. Take for example this |
| extract of |
| a link:http://groovy.dzone.com/news/domain-specific-language-unit-[Unit |
| manipulation DSL] dealing with operator overloading: |
| |
| [source,groovy] |
| --------------------------------------------------------------------------------- |
| Number.metaClass.multiply = { Amount amount -> amount.times(delegate) } |
| Number.metaClass.div = { Amount amount -> amount.inverse().times(delegate) } |
| |
| Amount.metaClass.div = { Number factor -> delegate.divide(factor) } |
| Amount.metaClass.div = { Amount factor -> delegate.divide(factor) } |
| Amount.metaClass.multiply = { Number factor -> delegate.times(factor) } |
| Amount.metaClass.power = { Number factor -> delegate.pow(factor) } |
| Amount.metaClass.negative = { -> delegate.opposite() } |
| --------------------------------------------------------------------------------- |
| |
| The repetition, here, looks obvious. But with the ExpandoMetaClass DSL, |
| we can streamline the code by regrouping the operators per type: |
| |
| [source,groovy] |
| ------------------------------------------------------------------ |
| Number.metaClass { |
| multiply { Amount amount -> amount.times(delegate) } |
| div { Amount amount -> amount.inverse().times(delegate) } |
| } |
| |
| Amount.metaClass { |
| div << { Number factor -> delegate.divide(factor) } |
| div << { Amount factor -> delegate.divide(factor) } |
| multiply { Number factor -> delegate.times(factor) } |
| power { Number factor -> delegate.pow(factor) } |
| negative { -> delegate.opposite() } |
| } |
| ------------------------------------------------------------------ |
| |
| A `metaClass()` method takes a closure as single argument, containing |
| the various definitions of the methods and properties, instead of |
| repeating the `Type.metaClass` on each line. When there is just one |
| method of a given name, use the pattern `methodName { /* closure */ }`, |
| but when there are several, you should use the append operator and |
| follow the patten `methodName << { /* closure */ }`. Static methods can |
| also be added through this mechanism, so instead of the classical |
| approach: |
| |
| [source,groovy] |
| --------------------------------------------------------- |
| // add a fqn() method to Class to get the fully |
| // qualified name of the class (ie. simply Class#getName) |
| Class.metaClass.static.fqn = { delegate.name } |
| |
| assert String.fqn() == "java.lang.String" |
| --------------------------------------------------------- |
| |
| You can now do: |
| |
| [source,groovy] |
| ----------------------------- |
| Class.metaClass { |
| 'static' { |
| fqn { delegate.name } |
| } |
| } |
| ----------------------------- |
| |
| Note here that you have to quote the `static` keyword, to avoid this |
| construct to look like a static initializer. For one off method |
| addition, the classical approach is obviously more concise, but when you |
| have several methods to add, the EMC DSL makes sense. |
| |
| The usual approach for adding properties to existing classes through |
| ExpandoMetaClass is to add a getter and a setter as methods. For |
| instance, say you want to add a method that counts the number of words |
| in a text file, you could try this: |
| |
| [source,groovy] |
| ------------------------------------ |
| File.metaClass.getWordCount = { |
| delegate.text.split(/\w/).size() |
| } |
| |
| new File('myFile.txt').wordCount |
| ------------------------------------ |
| |
| When there is some logic inside the getter, this is certainly the best |
| approach, but when you just want to have new properties holding simple |
| values, through the ExpandoMetaClass DSL, it is possible to define them. |
| In the following example, a `lastAccessed` property is added to |
| a `Car` class — each instance will have its property. Whenever a method |
| is called on that car, this property is updated with a newer timestamp. |
| |
| [source,groovy] |
| ------------------------------------------------------------------------ |
| class Car { |
| void turnOn() {} |
| void drive() {} |
| void turnOff() {} |
| } |
| |
| Car.metaClass { |
| lastAccessed = null |
| invokeMethod = { String name, args -> |
| def metaMethod = delegate.metaClass.getMetaMethod(name, args) |
| if (metaMethod) { |
| delegate.lastAccessed = new Date() |
| metaMethod.doMethodInvoke(delegate, args) |
| } else { |
| throw new MissingMethodException(name, delegate.class, args) |
| } |
| } |
| } |
| |
| def car = new Car() |
| println "Last accessed: ${car.lastAccessed ?: 'Never'}" |
| |
| car.turnOn() |
| println "Last accessed: ${car.lastAccessed ?: 'Never'}" |
| |
| car.drive() |
| sleep 1000 |
| println "Last accessed: ${car.lastAccessed ?: 'Never'}" |
| |
| sleep 1000 |
| car.turnOff() |
| println "Last accessed: ${car.lastAccessed ?: 'Never'}" |
| ------------------------------------------------------------------------ |
| |
| In our example, in the DSL, we access that property through |
| the `delegate` of the closure, |
| with `delegate.lastAccessed = new Date()`. And we intercept any method |
| call thanks to `invokeMethod()`, delegating to the original method for |
| the call, and throwing an exception in case the method doesn't exist. |
| Later on, you can see by executing this script that `lastAccessed` is |
| updated as soon as we call a method on our instance. |
| |
| [[Groovy16releasenotes-Runtimemixins]] |
| === Runtime mixins |
| |
| Last metaprogramming feature we'll cover today: runtime |
| mixins. `@Mixin` allowed you to mixin new behavior to classes you owned |
| and were designing. But you could not mixin anything to types you didn't |
| own. Runtime mixins propose to fill that gap by letting you add a mixin |
| on any type at runtime. If we think again about our example of vehicles |
| with some mixed-in capabilities, if we didn't _own_ James Bond's vehicle |
| and give it some diving ability, we could use this mechanism: |
| |
| [source,groovy] |
| --------------------------------------------------- |
| // provided by a third-party |
| interface Vehicle { |
| String getName() |
| } |
| |
| // provided by a third-party |
| class JamesBondVehicle implements Vehicle { |
| String getName() { "James Bond's vehicle" } |
| } |
| |
| JamesBondVehicle.mixin DivingAbility, FlyingAbility |
| |
| assert new JamesBondVehicle().fly() == |
| "I'm the James Bond's vehicle and I fly!" |
| assert new JamesBondVehicle().dive() == |
| "I'm the James Bond's vehicle and I dive!" |
| --------------------------------------------------- |
| |
| One or more mixins can be passed as argument to the |
| static `mixin()` method added by Groovy on `Class`. |
| |
| [[Groovy16releasenotes-JSR-223GroovyScriptingEngine]] |
| == JSR-223 Groovy Scripting Engine |
| |
| Before Groovy 1.6, if you wanted to integrate Groovy in your Java |
| projects through JSR-223 / `javax.script.*`, you had to download a |
| Groovy script engine implementation from java.net, and put the JAR in |
| your classpath. This additional step wasn't very developer friendly, |
| requiring some additional work — the JAR wasn't even provided in the |
| Groovy distribution. Thankfully, 1.6 comes with an implementation of |
| the `javax.script.*` APIs. |
| |
| Below, you'll find an example evaluating Groovy expressions (the code is |
| in Groovy, but it's straightforward to convert it back to Java): |
| |
| [source,groovy] |
| ---------------------------------------------- |
| import javax.script.* |
| |
| def manager = new ScriptEngineManager() |
| def engine = manager.getEngineByName("groovy") |
| |
| assert engine.evaluate("2 + 3") == 5 |
| ---------------------------------------------- |
| |
| Please note that the `javax.script.*` APIs are available only on Java 6. |
| |
| [[Groovy16releasenotes-JMXBuilder]] |
| == JMX Builder |
| |
| Originating as an link:http://code.google.com/p/groovy-jmx-builder/[external |
| Open-Source project] hosted on Google Code, JMX Builder has been |
| integrated in Groovy 1.6, to simplify the life of developers needing to |
| interact or expose JMX services. JMX Builder features: |
| |
| * Domain Specific Language (DSL) for JMX API using Builder pattern |
| * Simplified JMX API's programmability |
| * Declaratively expose Java/Groovy objects as JMX managed MBeans |
| * Support class-embedded or explicit descriptors |
| * Inherent support for JMX's event model |
| * Seamlessly create JMX event broadcasters |
| * Attach event listeners as inline closures |
| * Use Groovy's dynamic nature to easily react to JMX events |
| notifications |
| * Provides a flexible registration policy for MBean |
| * No special interfaces or class path restrictions |
| * Shields developer from complexity of JMX API |
| * Exposes attribute, constructors, operations, parameters, and |
| notifications |
| * Simplifies the creation of connector servers and connector clients |
| * Support for exporting JMX timers |
| |
| You can find link:../jmx.html[more information on JMX Builder] and its very extensive coverage of the JMX |
| system. Lots of examples will show you how to create a JMX connector |
| server or client, how to easily export POGOs as JMX managed beans, how |
| to listen to JMX events, and much more. |
| |
| [[Groovy16releasenotes-ImprovedOSGisupport]] |
| == Improved OSGi support |
| |
| The Groovy jar files are released with correct OSGi metadata, so they |
| can be loaded as a bundle into any OSGi compliant container, such as |
| Eclipse Equinox or Apache Felix. |
| |
| [[Groovy16releasenotes-Summary]] |
| == Summary |
| |
| Groovy continues its march towards the goal of *simplifying the life of |
| developers*, providing various new features and improvements in this new |
| release: AST transformations reducing dramatically the number of lines |
| of code to express certain concerns and patterns and opening the |
| language to developers for further extension, several *metaprogramming |
| enhancements to streamline your code* and let you write *more expressive |
| business rules*, and *support for common enterprise APIs* such as Java |
| 6's scripting APIs, JMX management system, or OSGi's programming model. |
| All of this is done obviously *without compromising on the seamless |
| integration with Java*, and furthermore, with a *level of performance |
| way higher than previous releases*. |