One of the great features of Gradle is the support for plugins. A plugin can contain tasks, configurations, properties, methods, concepts, and more to add extra functionality to our projects. For example, if we apply the Java plugin to our project, we can immediately invoke the compile, test, and build tasks. Also, we have new dependency configurations we can use and extra properties we can configure. The Java plugin itself applies the java-base plugin. The java-base plugin doesn't introduce tasks, but the concept of source sets. This is a good pattern for creating our own plugins, where a base plugin introduces new concepts and another plugin derives from the base plugin and adds explicit build logic-like tasks.
So a plugin is a good way to distribute build logic that we want to share between projects. We can write our own plugin, give it an explicit version, and publish it to, for example, a repository. Other projects can then re-use the functionality by simply applying the plugin to a project. We can create our own plugins and use them in our projects. We start by defining the plugin in the build file.
We can create a custom plugin right in the project build file. Similar to a custom task, we can add a new class definition with the logic of the plugin. We must implement the org.gradle.api.Plugin<T>
interface. The interface has one method named apply()
. When we write our own plugin, we must override this method. The method accepts an object as a parameter. The type of the object is the same as the generic type T
. When we create a plugin for projects, the type Project
is used. We can also write plugins for other Gradle types, like tasks. Then we must use the Task
type.
We are going to create a simple plugin that will print out the Gradle version. The plugin adds a new info
task to the project. The following sample build file defines a new plugin with the name InfoPlugin
. We override the apply()
method and add a new task to the project, with the name info
. This task prints out the Gradle version. At the top of the build file, we use the apply()
method and reference the plugin by the name InfoPlugin
, which is the class name of the plugin:
apply plugin: InfoPlugin class InfoPlugin implements Plugin<Project> { void apply(Project project) { project.task('info') << { println "Running Gradle: $project.gradle.gradleVersion" } } }
From the command line, we can invoke the info
task when we run Gradle. We can see the Gradle version in the following output:
$ gradle info :info Running Gradle: 1.1 BUILD SUCCESSFUL Total time: 2.503 secs
The info
task always prints the same text before the Gradle version. We can rewrite the task and make the text configurable. A Gradle Project has an associated ExtensionContainer
object. This object can hold all settings and properties we want to pass to a plugin. We can add a Java Bean to ExtensionContainer
so that we can configure the bean's properties from the build file. The Java Bean is a so-called extension object.
In our sample build file, we first add a new class InfoPluginExtension
with a property prefix of type String
. This is the Java Bean-compliant class we add to ExtensionContainer
. In the
apply()
method, we use the create()
method of ExtensionContainer
to add InfoPluginExtension
with the name info
to the project. In the build file, we configure the prefix
property using the info
configuration closure. Or we can simply reference the prefix
property through the info
extension object:
apply plugin: InfoPlugin // Configure the InfoPlugin through the // InfoPluginExtension. info { prefix = 'Gradle version' } // Or info.prefix = 'Gradle version' class InfoPlugin implements Plugin<Project> { void apply(Project project) { // Add the Java Bean InfoPluginExtension with the // name info to the project ExtensionContainer. project.extensions.create('info', InfoPluginExtension) project.task('info') << { // Use project.info.prefix from the extension. println "$project.info.prefix: $project.gradle.gradleVersion" } } } class InfoPluginExtension { String prefix = 'Running Gradle' }
If we run the info
task, we see our configured prefix in the output:
3.145.45.5