Introduction to Groovy DSL using an example from Gradle

If you’ve used the Gradle build system, you’ve probably already used and benefited from the DSL features of the Groovy language. In this article, let’s look at such an example.

Let’s take the following DSL snippet from the Gradle configuration.

plugins {
    id 'java'
}

In chapter plugins configures the Gradle plugins used in your build and mentions any plugins you want to apply. Let’s understand what’s going on under the hood to get it working with a not-so-complicated example.

def plugins (def pluginConfig) {
    println "Plugins called"
}

//--------------- DSL
plugins {
    id 'java'
}

When we run the above code, we see that the console displays “Plugins called” (plugins called). We understand that plugins is a method. Look at an alternative way to call a method plugins.

plugins({
    id 'java'
})

It is now clear that the content inside ‘{}’ is passed as an argument to the method plugins. Such blocks of code in Groovy are called closures. If your method’s last argument (it may be the only one) is a closure, Groovy allows you to write them outside of parentheses. Thus, the above code can be written in the following way.

plugins() {
    id 'java'
}

Also, Groovy allows parentheses to be omitted if the method has at least one argument, which is what happened in this case. Thus, we get the original code used in our DSL.

plugins {
    id 'java'
}

Since we want to add plugins to the project, let’s create a structure to store information about it.

class Project {
    List<Plugin> plugins = []
}

import groovy.transform.ToString

@ToString(includePackage = false)
class Plugin {
    String id
}

Now we have to create an instance of the class Plugin and add it to plugins Project. As you may have guessed id 'java' means we are calling the identification method with ‘java’ as an argument. Let’s add this method to the class Projectas it seems like the right place to put it.

class Project {
    List<Plugin> plugins = []

    def id(String pluginId) {
        println "Adding plugin $pluginId"
        plugins << new Plugin(id: pluginId)
    }
}

Let’s update our plugin method to call the closure on the instance project.

def plugins(def pluginConfig) {
    Project project = new Project()
    println "Plugins called"
    project.with pluginConfig
}

The console should display the message “Adding plugin java”. Here we are using the with method to provide the closure we received as an argument to the ‘project’ object (not to this script’s instance).

Let’s add another plugin to our DSL and make sure it works as expected. At the same time, we will display all the plugins from the project.

def plugins(def pluginConfig) {
    Project project = new Project()
    println "Plugins called"
    project.with pluginConfig
    println project.plugins
}

//---------------
plugins{
    id 'java'
    id 'groovy'
}

You should see the following on the console:

Plugins called
Adding plugin java
Adding plugin groovy
[Plugin(java), Plugin(groovy)]

Of course, a full DSL will be more complex. Here I tried to convey the essence of the idea with the help of the most simple examples.


In conclusion, we invite everyone to open class “Shared Libraries in Jenkins”, which will take place tomorrow at 20:00. In this lesson, we will see how to extend pipelines in Jenkins using external libraries and learn how to write them. The lesson will be especially useful for DevOps engineers and Java developers who want to learn how to create and customize builds of Java Backend projects.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *