Gradle 提供了用於維護物件集合的類型,旨在良好地擴展 Gradle 的 DSL 並提供有用的功能,例如延遲組態。

可用的集合

這些集合類型用於管理物件集合,特別是在建置腳本和外掛程式的上下文中

  1. DomainObjectSet<T>:代表類型 T 的物件集合。此集合不允許重複元素,您可以在集合中新增、移除和查詢物件。

  2. NamedDomainObjectSet<T>DomainObjectSet 的特化版本,其中每個物件都有一個相關聯的唯一名稱。這通常用於需要透過名稱唯一識別每個元素的集合。

  3. NamedDomainObjectList<T>:類似於 NamedDomainObjectSet,但代表物件列表,其中順序很重要。每個元素都有一個相關聯的唯一名稱,您可以透過索引以及名稱存取元素。

  4. NamedDomainObjectContainer<T>:用於管理類型 T 物件的容器,其中每個物件都有一個唯一名稱。此容器提供透過名稱新增、移除和查詢物件的方法。

  5. ExtensiblePolymorphicDomainObjectContainer<T>NamedDomainObjectContainer 的擴展,允許您為不同類型的物件定義實例化策略。當您有一個可以容納多種類型物件的容器,並且想要控制每種類型物件的實例化方式時,這非常有用。

這些類型通常在 Gradle 外掛程式和建置腳本中使用,以管理物件集合,例如任務、組態或自訂領域物件。

1. DomainObjectSet

DomainObjectSet 僅包含一組可組態的物件。

NamedDomainObjectContainer 相比,DomainObjectSet 不管理集合中的物件。它們需要手動建立和新增。

您可以使用 ObjectFactory.domainObjectSet() 方法建立實例

build.gradle.kts
abstract class MyPluginExtensionDomainObjectSet {
    // Define a domain object set to hold strings
    val myStrings: DomainObjectSet<String> = project.objects.domainObjectSet(String::class)

    // Add some strings to the domain object set
    fun addString(value: String) {
        myStrings.add(value)
    }
}
build.gradle
abstract class MyPluginExtensionDomainObjectSet {
    // Define a domain object set to hold strings
    DomainObjectSet<String> myStrings = project.objects.domainObjectSet(String)

    // Add some strings to the domain object set
    void addString(String value) {
        myStrings.add(value)
    }
}

2. NamedDomainObjectSet

NamedDomainObjectSet 包含一組可組態的物件,其中每個元素都有一個相關聯的名稱。

這與 NamedDomainObjectContainer 相似,但 NamedDomainObjectSet 不管理集合中的物件。它們需要手動建立和新增。

您可以使用 ObjectFactory.namedDomainObjectSet() 方法建立實例。

build.gradle.kts
abstract class Person(val name: String)

abstract class MyPluginExtensionNamedDomainObjectSet {
    // Define a named domain object set to hold Person objects
    private val people: NamedDomainObjectSet<Person> = project.objects.namedDomainObjectSet(Person::class)

    // Add a person to the set
    fun addPerson(name: String) {
        people.plus(name)
    }
}
build.gradle
abstract class Person {
    String name
}

abstract class MyPluginExtensionNamedDomainObjectSet {
    // Define a named domain object set to hold Person objects
    NamedDomainObjectSet<Person> people = project.objects.namedDomainObjectSet(Person)

    // Add a person to the set
    void addPerson(String name) {
        people.create(name)
    }
}

3. NamedDomainObjectList

NamedDomainObjectList 包含一個可組態物件的列表,其中每個元素都有一個相關聯的名稱。

這與 NamedDomainObjectContainer 相似,但 NamedDomainObjectList 不管理集合中的物件。它們需要手動建立和新增。

您可以使用 ObjectFactory.namedDomainObjectList() 方法建立實例。

build.gradle.kts
abstract class Person(val name: String)

abstract class MyPluginExtensionNamedDomainObjectList {
    // Define a named domain object list to hold Person objects
    private val people: NamedDomainObjectList<Person> = project.objects.namedDomainObjectList(Person::class)

    // Add a person to the container
    fun addPerson(name: String) {
        people.plus(name)
    }
}
build.gradle
abstract class Person {
    String name
}

abstract class MyPluginExtensionNamedDomainObjectList {
    // Define a named domain object container to hold Person objects
    NamedDomainObjectList<Person> people = project.container(Person)

    // Add a person to the container
    void addPerson(String name) {
        people.create(name: name)
    }
}

4. NamedDomainObjectContainer

NamedDomainObjectContainer 管理一組物件,其中每個元素都有一個相關聯的名稱。

容器負責建立和組態元素,並提供一個 DSL,建置腳本可以使用它來定義和組態元素。它旨在容納本身可組態的物件,例如一組自訂 Gradle 物件。

Gradle 在整個 API 中廣泛使用 NamedDomainObjectContainer 類型。例如,用於管理專案任務的 project.tasks 物件是一個 NamedDomainObjectContainer<Task>

您可以使用 ObjectFactory 服務建立容器實例,該服務提供 ObjectFactory.domainObjectContainer() 方法。這也可以使用 Project.container() 方法,但在自訂 Gradle 類型中,通常最好使用注入的 ObjectFactory 服務,而不是傳遞 Project 實例。

您也可以使用唯讀受管屬性建立容器實例。

build.gradle.kts
abstract class Person(val name: String)

abstract class MyPluginExtensionNamedDomainObjectContainer {
    // Define a named domain object container to hold Person objects
    private val people: NamedDomainObjectContainer<Person> = project.container(Person::class)

    // Add a person to the container
    fun addPerson(name: String) {
        people.create(name)
    }
}
build.gradle
abstract class Person {
    String name
}

abstract class MyPluginExtensionNamedDomainObjectContainer {
    // Define a named domain object container to hold Person objects
    NamedDomainObjectContainer<Person> people = project.container(Person)

    // Add a person to the container
    void addPerson(String name) {
        people.create(name: name)
    }
}

為了將類型與任何 domainObjectContainer() 方法一起使用,它必須是

  • 受命名的受管類型;或

  • 公開一個名為 “name” 的屬性,作為物件的唯一且恆定的名稱。方法的 domainObjectContainer(Class) 變體透過呼叫類的建構子來建立新實例,該建構子接受字串引數,即物件的所需名稱。

以這種方式建立的物件被視為自訂 Gradle 類型,因此可以使用本章討論的功能,例如服務注入或受管屬性。

請參閱上面的連結,了解允許自訂實例化策略的 domainObjectContainer() 方法變體

public interface DownloadExtension {
    NamedDomainObjectContainer<Resource> getResources();
}

public interface Resource {
    // Type must have a read-only 'name' property
    String getName();

    Property<URI> getUri();

    Property<String> getUserName();
}

對於每個容器屬性,Gradle 會自動在 Groovy 和 Kotlin DSL 中新增一個區塊,您可以使用它來組態容器的內容

build.gradle.kts
plugins {
    id("org.gradle.sample.download")
}

download {
    // Can use a block to configure the container contents
    resources {
        register("gradle") {
            uri = uri("https://gradle.org")
        }
    }
}
build.gradle
plugins {
    id("org.gradle.sample.download")
}

download {
    // Can use a block to configure the container contents
    resources {
        register('gradle') {
            uri = uri('https://gradle.org')
        }
    }
}

5. ExtensiblePolymorphicDomainObjectContainer

ExtensiblePolymorphicDomainObjectContainer 是一個 NamedDomainObjectContainer,它允許您為不同類型的物件定義實例化策略。

您可以使用 ObjectFactory.polymorphicDomainObjectContainer() 方法建立實例

build.gradle.kts
abstract class Animal(val name: String)

class Dog(name: String, val breed: String) : Animal(name)

abstract class MyPluginExtensionExtensiblePolymorphicDomainObjectContainer(objectFactory: ObjectFactory) {
    // Define a container for animals
    private val animals: ExtensiblePolymorphicDomainObjectContainer<Animal> = objectFactory.polymorphicDomainObjectContainer(Animal::class)

    // Add a dog to the container
    fun addDog(name: String, breed: String) {
        var dog : Dog = Dog(name, breed)
        animals.add(dog)
    }
}
build.gradle
abstract class Animal {
    String name
}

abstract class Dog extends Animal {
    String breed
}

abstract class MyPluginExtensionExtensiblePolymorphicDomainObjectContainer {
    // Define a container for animals
    ExtensiblePolymorphicDomainObjectContainer<Animal> animals

    MyPluginExtensionExtensiblePolymorphicDomainObjectContainer(ObjectFactory objectFactory) {
        // Create the container
        animals = objectFactory.polymorphicDomainObjectContainer(Animal)
    }

    // Add a dog to the container
    void addDog(String name, String breed) {
        animals.create(Dog, name: name, breed: breed)
    }
}