api / org.gradle.api.plugins / ExtensionAware

ExtensionAware

interface ExtensionAware

Objects that can be extended at runtime with other objects.

 // Extensions are just plain objects, there is no interface/type class MyExtension { String foo MyExtension(String foo) { this.foo = foo } } // Add new extensions via the extension container project.extensions.create('custom', MyExtension, "bar") // («name», «type», «constructor args», …) // extensions appear as properties on the target object by the given name assert project.custom instanceof MyExtension assert project.custom.foo == "bar" // also via a namespace method project.custom { assert foo == "bar" foo = "other" } assert project.custom.foo == "other" // Extensions added with the extension container's create method are themselves extensible assert project.custom instanceof ExtensionAware project.custom.extensions.create("nested", MyExtension, "baz") assert project.custom.nested.foo == "baz" // All extension aware objects have a special “ext” extension of type ExtraPropertiesExtension assert project.hasProperty("myProperty") == false project.ext.myProperty = "myValue" // Properties added to the “ext” extension are promoted to the owning object assert project.myProperty == "myValue" 
Many Gradle objects are extension aware. This includes; projects, tasks, configurations, dependencies etc.

For more on adding & creating extensions, see ExtensionContainer.

For more on extra properties, see ExtraPropertiesExtension.

An ExtensionAware object has several 'scopes' that Gradle searches for properties. These scopes are:

Functions

getExtensions

abstract fun getExtensions(): ExtensionContainer

The container of extensions.

Extension Properties

extra

val ExtensionAware.extra: ExtraPropertiesExtension

The extra properties extension in this object's extension container.

Extension Functions

configure

fun <T : Any> ExtensionAware.configure(configuration: T.() -> Unit): Unit

Executes the given configuration block against the extension of the specified type.

the

fun <T : Any> ExtensionAware.the(): T

Returns the extension of the specified type.

fun <T : Any> ExtensionAware.the(extensionType: KClass<T>): T

Returns the extension of the specified extensionType.

Inheritors

Project

interface Project : Comparable<Project>, ExtensionAware, PluginAware

This interface is the main API you use to interact with Gradle from your build file. From a Project, you have programmatic access to all of Gradle's features.

Lifecycle

There is a one-to-one relationship between a Project and a {@value #DEFAULT_BUILD_FILE} file. During build initialisation, Gradle assembles a Project object for each project which is to participate in the build, as follows:

  • Create a org.gradle.api.initialization.Settings instance for the build.
  • Evaluate the {@value org.gradle.api.initialization.Settings#DEFAULT_SETTINGS_FILE} script, if present, against the org.gradle.api.initialization.Settings object to configure it.
  • Use the configured org.gradle.api.initialization.Settings object to create the hierarchy of Project instances.
  • Finally, evaluate each Project by executing its {@value #DEFAULT_BUILD_FILE} file, if present, against the project. The projects are evaluated in breadth-wise order, such that a project is evaluated before its child projects. This order can be overridden by calling #evaluationDependsOnChildren() or by adding an explicit evaluation dependency using #evaluationDependsOn(String).
Tasks

A project is essentially a collection of Task objects. Each task performs some basic piece of work, such as compiling classes, or running unit tests, or zipping up a WAR file. You add tasks to a project using one of the create() methods on TaskContainer, such as TaskContainer#create(String). You can locate existing tasks using one of the lookup methods on TaskContainer, such as org.gradle.api.tasks.TaskCollection#getByName(String).

Dependencies

A project generally has a number of dependencies it needs in order to do its work. Also, a project generally produces a number of artifacts, which other projects can use. Those dependencies are grouped in configurations, and can be retrieved and uploaded from repositories. You use the org.gradle.api.artifacts.ConfigurationContainer returned by #getConfigurations() method to manage the configurations. The returned by #getDependencies() method to manage the dependencies. The org.gradle.api.artifacts.dsl.ArtifactHandler returned by #getArtifacts() method to manage the artifacts. The org.gradle.api.artifacts.dsl.RepositoryHandler returned by method to manage the repositories.

Multi-project Builds

Projects are arranged into a hierarchy of projects. A project has a name, and a fully qualified path which uniquely identifies it in the hierarchy.

Plugins

Plugins can be used to modularise and reuse project configuration. Plugins can be applied using the PluginAware#apply(java.util.Map) method, or by using the org.gradle.plugin.use.PluginDependenciesSpec plugins script block.

Properties

Gradle executes the project's build file against the Project instance to configure the project. Any property or method which your script uses is delegated through to the associated Project object. This means, that you can use any of the methods and properties on the Project interface directly in your script.

For example:

 defaultTasks('some-task') // Delegates to Project.defaultTasks() reportsDir = file('reports') // Delegates to Project.file() and the Java Plugin 

You can also access the Project instance using the project property. This can make the script clearer in some cases. For example, you could use project.name rather than name to access the project's name.

A project has 5 property 'scopes', which it searches for properties. You can access these properties by name in your build file, or by calling the project's #property(String) method. The scopes are:

  • The Project object itself. This scope includes any property getters and setters declared by the Project implementation class. For example, #getRootProject() is accessible as the rootProject property. The properties of this scope are readable or writable depending on the presence of the corresponding getter or setter method.
  • The extra properties of the project. Each project maintains a map of extra properties, which can contain any arbitrary name -> value pair. Once defined, the properties of this scope are readable and writable. See extra properties for more details.
  • The extensions added to the project by the plugins. Each extension is available as a read-only property with the same name as the extension.
  • The convention properties added to the project by the plugins. A plugin can add properties and methods to a project through the project's Convention object. The properties of this scope may be readable or writable, depending on the convention objects.
  • The tasks of the project. A task is accessible by using its name as a property name. The properties of this scope are read-only. For example, a task called compile is accessible as the compile property.
  • The extra properties and convention properties are inherited from the project's parent, recursively up to the root project. The properties of this scope are read-only.

When reading a property, the project searches the above scopes in order, and returns the value from the first scope it finds the property in. If not found, an exception is thrown. See #property(String) for more details.

When writing a property, the project searches the above scopes in order, and sets the property in the first scope it finds the property in. If not found, an exception is thrown. See #setProperty(String, Object) for more details.

Extra Properties All extra properties must be defined through the "ext" namespace. Once an extra property has been defined, it is available directly on the owning object (in the below case the Project, Task, and sub-projects respectively) and can be read and updated. Only the initial declaration that needs to be done via the namespace.
 project.ext.prop1 = "foo" task doStuff { ext.prop2 = "bar" } subprojects { ext.${prop3} = false } 
Reading extra properties is done through the "ext" or through the owning object.
 ext.isSnapshot = version.endsWith("-SNAPSHOT") if (isSnapshot) { // do snapshot stuff } 
Dynamic Methods

A project has 5 method 'scopes', which it searches for methods:

  • The Project object itself.
  • The build file. The project searches for a matching method declared in the build file.
  • The extensions added to the project by the plugins. Each extension is available as a method which takes a closure or org.gradle.api.Action as a parameter.
  • The convention methods added to the project by the plugins. A plugin can add properties and method to a project through the project's Convention object.
  • The tasks of the project. A method is added for each task, using the name of the task as the method name and taking a single closure or org.gradle.api.Action parameter. The method calls the Task#configure(groovy.lang.Closure) method for the associated task with the provided closure. For example, if the project has a task called compile, then a method is added with the following signature: void compile(Closure configureClosure).
  • The methods of the parent project, recursively up to the root project.
  • A property of the project whose value is a closure. The closure is treated as a method and called with the provided parameters. The property is located as described above.

Task

interface Task : Comparable<Task>, ExtensionAware

A Task represents a single atomic piece of work for a build, such as compiling classes or generating javadoc.

Each task belongs to a Project. You can use the various methods on to create and lookup task instances. For example, creates an empty task with the given name. You can also use the task keyword in your build file:

 task myTask task myTask { configure closure } task myTask(type: SomeType) task myTask(type: SomeType) { configure closure } 

Each task has a name, which can be used to refer to the task within its owning project, and a fully qualified path, which is unique across all tasks in all projects. The path is the concatenation of the owning project's path and the task's name. Path elements are separated using the {@value org.gradle.api.Project#PATH_SEPARATOR} character.

Task Actions

A Task is made up of a sequence of Action objects. When the task is executed, each of the actions is executed in turn, by calling Action#execute. You can add actions to a task by calling or #doLast(Action).

Groovy closures can also be used to provide a task action. When the action is executed, the closure is called with the task as parameter. You can add action closures to a task by calling #doFirst(groovy.lang.Closure) or #doLast(groovy.lang.Closure).

There are 2 special exceptions which a task action can throw to abort execution and continue without failing the build. A task action can abort execution of the action and continue to the next action of the task by throwing a org.gradle.api.tasks.StopActionException. A task action can abort execution of the task and continue to the next task by throwing a org.gradle.api.tasks.StopExecutionException. Using these exceptions allows you to have precondition actions which skip execution of the task, or part of the task, if not true.

Task Dependencies and Task Ordering

A task may have dependencies on other tasks or might be scheduled to always run after another task. Gradle ensures that all task dependencies and ordering rules are honored when executing tasks, so that the task is executed after all of its dependencies and any "must run after" tasks have been executed.

Dependencies to a task are controlled using #dependsOn(Object...) or #setDependsOn(Iterable), and #mustRunAfter(Object...), #setMustRunAfter(Iterable), #shouldRunAfter(Object...) and #setShouldRunAfter(Iterable) are used to specify ordering between tasks. You can use objects of any of the following types to specify dependencies and ordering:

  • A String, CharSequence or groovy.lang.GString task path or name. A relative path is interpreted relative to the task's Project. This allows you to refer to tasks in other projects.
  • A Task.
  • A closure. The closure may take a Task as parameter. It may return any of the types listed here. Its return value is recursively converted to tasks. A null return value is treated as an empty collection.
  • A TaskDependency object.
  • A Buildable object.
  • A org.gradle.api.file.RegularFileProperty or org.gradle.api.file.DirectoryProperty.
  • A Iterable, Collection, Map or array. May contain any of the types listed here. The elements of the iterable/collection/map/array are recursively converted to tasks.
  • A Callable. The call() method may return any of the types listed here. Its return value is recursively converted to tasks. A null return value is treated as an empty collection.
Using a Task in a Build File Dynamic Properties

A Task has 4 'scopes' for properties. You can access these properties by name from the build file or by calling the #property(String) method. You can change the value of these properties by calling the #setProperty(String, Object) method.

  • The Task object itself. This includes any property getters and setters declared by the Task implementation class. The properties of this scope are readable or writable based on the presence of the corresponding getter and setter methods.
  • The extensions added to the task by plugins. Each extension is available as a read-only property with the same name as the extension.
  • The convention properties added to the task by plugins. A plugin can add properties and methods to a task through the task's Convention object. The properties of this scope may be readable or writable, depending on the convention objects.
  • The extra properties of the task. Each task object maintains a map of additional properties. These are arbitrary name -> value pairs which you can use to dynamically add properties to a task object. Once defined, the properties of this scope are readable and writable.
Dynamic Methods

A Plugin may add methods to a Task using its Convention object.

Parallel Execution

By default, tasks are not executed in parallel unless a task is waiting on asynchronous work and another task (which is not dependent) is ready to execute. Parallel execution can be enabled by the --parallel flag when the build is initiated. In parallel mode, the tasks of different projects (i.e. in a multi project build) are able to be executed in parallel.