Gradle at its core intentionally provides very little for real world automation. All of the useful
features, like the ability to compile Java code, are added by plugins.
Plugins add new tasks (e.g. JavaCompile
), domain objects (e.g.
SourceSet
), conventions (e.g. Java source is located at
src/main/java
) as well as extending core objects and objects from other plugins.
In this chapter we will discuss how to use plugins and the terminology and concepts surrounding plugins.
There are two general types of plugins in Gradle, script plugins and binary plugins.
Script plugins are additional build scripts that further configure the build and usually implement a declarative approach to
manipulating the build. They are typically used within a build although they can be externalized and accessed from a remote
location. Binary plugins are classes that implement the Plugin
interface and adopt a programmatic
approach to manipulating the build. Binary plugins can reside within a build script, within the project hierarchy or externally
in a plugin jar.
Plugins are said to be applied, which is done via the Project.apply()
method.
Script plugins can be applied from a script on the local filesystem or at a remote location. Filesystem locations are relative to the project directory, while remote script locations are specified with an HTTP URL. Multiple script plugins (of either form) can be applied to a given build.
Core plugins register a short name. In the above case, we are using the short name
‘java
’ to apply the JavaPlugin
.
Plugins also have a plugin id that takes a fully qualified
form like com.github.foo.bar
, although some legacy plugins may still utilize
the short, unqualified form.
This method can also accept a class to identify the plugin:
The JavaPlugin
symbol in the above sample refers to the the JavaPlugin
.
This class does not strictly need to be import as the org.gradle.api.plugins
package is automatically imported in all build scripts
(see Appendix E, Existing IDE Support and how to cope without it). Furthermore, it is not necessary to append .class
to identify a class literal in Groovy as it is in Java.
The application of plugins is idempotent. That is, a plugin can be applied multiple times. If the plugin has previously been applied, any further applications will have no effect.
A plugin is simply any class that implements the Plugin
interface. Gradle provides
the core plugins as part of its distribution so simply applying the plugin as above is all you need to do.
However, non-core binary plugins need to be available to the build classpath before they can be applied. This can
be achieved in a number of ways, including:
For more on defining your own plugins, see Chapter 59, Writing Custom Plugins.
The plugins DSL is currently incubating. Please be aware that the DSL and other configuration may change in later Gradle versions.
The new plugins DSL provides a more succinct and convenient way to declare plugin dependencies. It works with the
new Gradle plugin portal to provide easy access to both core and community
plugins. The plugins script block configures an instance of PluginDependenciesSpec
.
To apply a core plugin, the short name can be used:
To apply a community plugin from the portal, the fully qualified plugin id must be used:
Example 21.5. Applying a community plugin
build.gradle
plugins { id "com.jfrog.bintray" version "0.4.1" }
No further configuration is necessary. Specifically, there is no need to configure the buildscript classpath. Gradle will resolve the plugin in the plugin portal, locate it, and make it available to the build.
See PluginDependenciesSpec
for more information on using the Plugin DSL.
Gradle has a vibrant community of plugin developers who contribute plugins for a wide variety of capabilities. The Gradle plugin portal provides an interface for searching and exploring community plugins.
Applying a plugin to the project allows the plugin to extend the project's capabilities. It can do things such as:
Let's check this out:
Example 21.6. Tasks added by a plugin
build.gradle
apply plugin: 'java'
task show << {
println relativePath(compileJava.destinationDir)
println relativePath(processResources.destinationDir)
}
Output of gradle -q show
> gradle -q show build/classes/main build/resources/main
The Java plugin has added a compileJava
task and a processResources
task
to the project and configured the destinationDir
property of both of these tasks.
Plugins can pre-configure the project in smart ways to support convention-over-configuration. Gradle provides mechanisms and sophisticated support and it's a key ingredient in powerful-yet-concise build scripts.
We saw in the example above that the Java plugins adds a task named compileJava
that has
a property named destinationDir
(that configures where the compiled Java source should be placed).
The Java plugin defaults this property to point to build/classes/main
in the project directory.
This is an example of convention-over-configuration via a reasonable default.
We can change this property simply by giving it a new value.
Example 21.7. Changing plugin defaults
build.gradle
apply plugin: 'java' compileJava.destinationDir = file("$buildDir/output/classes") task show << { println relativePath(compileJava.destinationDir) }
Output of gradle -q show
> gradle -q show build/output/classes
However, it's likely that the compileJava
task is not the only task that needs to know where
the class files are.
The Java plugin adds the concept of source sets (see SourceSet
)
to describe the aspects of a set of source files, one aspect being where the class files should be written to when they are compiled.
The Java plugin maps the destinationDir
property of the compileJava
task to this aspect of the source set.
We can change where the class files are written to by configuring the source set.
Example 21.8. Plugin convention object
build.gradle
apply plugin: 'java' sourceSets.main.output.classesDir = file("$buildDir/output/classes") task show << { println relativePath(compileJava.destinationDir) }
Output of gradle -q show
> gradle -q show build/output/classes
In the example above, we applied the Java plugin which, among other things, did the following:
SourceSet
main
source set with default (i.e. conventional) values for properties
All of this happened during the “apply plugin: "java"
” step. In the example above, we changed
the desired location of the class files after this conventional configuration had been performed. Notice by the output with the example
that the value for compileJava.destinationDir
also changed to reflect the configuration change.
Consider the case where another task needs to consume the class files. If this task is configured to use the value from
sourceSets.main.output.classesDir
, then changing it in this location will update this
new task in addition to the compileJava
task whenever it is changed.
This ability to configure properties of objects to reflect the value of another object's task at all times (i.e. even when it changes) is known as “convention mapping”. It allows Gradle to provide conciseness through convention-over-configuration and sensible defaults yet not require complete reconfiguration if a conventional default needs to be changed. Without this, in the example above, we would have had to reconfigure every object that needs to work with the class files.
This chapter aims to serve as an introduction to plugins and Gradle and the role they play. For more information on the inner workings of plugins, see Chapter 59, Writing Custom Plugins.