Groovy Goodness: Customize Log Variable Name with Log AST Annotations

To add logging to a class with Groovy is easy. We apply one of the logging AST transformations and we get a variable in our class named log. We can invoke methods on the variable and the AST transformation will also automatically wrap those statement in a “if-logging-level-is-enabled” block. The transformation is even intelligent enough to do this only if Strings are added or a GString is used. If we want to use a different name than log we simply use the value parameter of the annotation. We assign the name we want to use and then we can use it in our code.

Code written with Groovy 2.1.3.

Original blog post

Gradle Goodness: Extending DSL

Gradle already has a powerful DSL, but Gradle wouldn’t be Gradle if we couldn’t extend the DSL ourselves. Maybe we have our own naming conventions in our company or we have a special problem domain we want to express in a Gradle build script. We can use the ExtensionContainer, available via project.extensions, to add new concepts to our build scripts. In the Standardizing your enterprise build environment webinar by Luke Daley some examples are shown on how to extend the DSL. Also in the samples folder of the Gradle distribution are examples on how to create a custom DSL.

Let’s first create a simple DSL extension. We first define a new class CommonDependencies with methods to define dependencies in a Java project. We want to use these methods with descriptive names in our build scripts. To add the class we use the create() method of the ExtensionContainer. The first argument is a name that needs to be unique within the build. The name can be used together with a configuration block in the script to invoke methods on the class we pass as the second argument. Finally we can pass constructor arguments for the class as last arguments of the create() method.

We can invoke the dependencies task from the command-line and we see all dependencies are resolved correctly:

We can also use a plugin to extend the Gradle DSL. In the plugin code we use the same project.extensions.create() method so it is more transparent for the user. We only have to apply the plugin to a project and we can use the extra DSL methods in the build script. Let’s create a simple plugin that will extend the DSL with the concept of a book and chapters. The following build script shows what we can do after we have applied the plugin:

To achieve this we first create the following directory structure with files:

The Book class will be added as DSL extension. The class has a method to set the title property and a method to add chapters which are Gradle project objects.

Next we create the BookPlugin class. The plugin will add the Book class as DSL extension. But we also create a task aggregate that will visit each chapter that is defined and then copies the content from the scr/html folder in the chapter project to the aggregate folder in the build folder. Finally we add a dist task that will simply archive the contents of the aggregated files.

We create the file to tell Gradle about our new plugin:

Our plugin is finished, so we can add a book project and some chapter projects. In the settings.gradle file we define an inclusion for these directories:

In the chapter directories we can add some sample content in the src/html directories. And in the book folder we create the following build.gradle file:

Now from the book folder we can run the aggregate and dist tasks. The end result is that all files from the chapter src/html folder are in the build/aggregate folder. And in the build/distributions folder we have the file containing the files.

Code written with Gradle 1.6.

Original blog post

Groovy Goodness: @DelegatesTo For Type Checking DSL

Groovy 2.1 introduced the @DelegatesTo annotation. With this annotation we can document a method and tell which class is responsible for executing the code we pass into the method. If we use @TypeChecked or @CompileStatic then the static type checker of the compiler will use this information to check at compile-time if the code is correct. And finally this annotation allows an IDE to give extra support like code completion.

Suppose we have the following class Reservation with the method submit(). The method accepts a closure with methods that need to be applied with the instance of the Reservation class. This is a very common pattern for writing simple DSLs in Groovy.

When we look at the code we might already see there is an error. In the Event.submitReservation() method we have the line reserved true, which will try to invoke the reserve() method of the Reservation class. But that method is not defined. When we run the application we get the expected error:

To get an error for this line at compile-time we must add some annotation so the Groovy compiler can do static type checking on our code. We change the code and get the following sample:

When the code is compiled we immediately get a compilation error:

Wow, this useful! We find errors in our DSL before the code is run.

When we create this code in an IDE like IntelliJ IDEA we also get code completion in the Reservation.submit() method invocation in the Event class. The following screenshot shows code completion and a red font for reserved to indicate the compilation error.

Code written in Groovy 2.1.3

Original blog post