Gradle:无法创建可扩展多态域对象容器

sy5wg1nm  于 2023-05-07  发布在  其他
关注(0)|答案(1)|浏览(145)

假设我有一个这样的扩展接口:

interface MyExtension {
    abstract val container: ExtensiblePolymorphicDomainObjectContainer<MyBaseClass>
}

当我尝试通过以下方式创建此扩展的示例时:

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val extension = project.extensions.create<MyExtension>("myExtension")
    }
}

Gradle(至少在7.6.1版本)似乎会因为无法创建扩展而无法应用MyPlugin,这反过来又是因为能够正确实现container属性。
这是Gradle的限制还是KotlinDSL需要解决方案(例如:使MyExtension成为一个抽象类,并专门注入一个ObjectFactory),还是我做错了什么?

mwkjh3gx

mwkjh3gx1#

Gradle只能在托管类型上创建特定类型的属性
这些是

  • Property<T>
  • RegularFileProperty
  • DirectoryProperty
  • ListProperty<T>
  • SetProperty<T>
  • MapProperty<K, V>
  • ConfigurableFileCollection
  • ConfigurableFileTree
  • DomainObjectSet<T>
  • NamedDomainObjectContainer<T>

Gradle v8.2中,将支持ExtensiblePolymorphicDomainObjectContainer<T>。在此之前,必须使用ObjectFactory手动创建它们。
一种方法是将ObjectFactory注入构造函数:

import javax.inject.Inject
import org.gradle.api.*
imports org.gradle.kotlin.dsl.*

abstract class MyExtension @Inject constructor(
  private val objects: ObjectFactory,
) {
  val container: ExtensiblePolymorphicDomainObjectContainer<MyBaseClass> =
    objects.polymorphicDomainObjectContainer()
}
专业提示:适用于NamedDomainObjectContainer的Kotlin DSL访问器

请注意,即使Gradle会自动创建NamedDomainObjectContainer属性,但手动创建并将其添加为扩展通常是一个好主意。

abstract class MyExtension @Inject constructor(
  private val objects: ObjectFactory,
) : ExtensionAware {
// *all* types that Gradle instantiates are automatically ExtensionAware,
// but adding the interface explicitly helps with IDE hints
  
  val namedContainer: NamedDomainObjectContainer<MyBaseClass> =
    objects.domainObjectContainer(MyBaseClass::class).also {
      extensions.add("namedContainer", it)
    }
}

这是冗长和怪异的-所以为什么麻烦?
通过添加namedContainer作为扩展,Gradle将为添加的任何元素自动生成一些类型安全的Kotlin DSL访问器。
因此,如果在您的插件中添加一个元素。

abstract class MyPlugin : Plugin<Project> {
  override fun apply(project: Project) {
    val extension = project.extensions.create<MyExtension>("myExtension")
    extension.namedContainer.register("anElement") { ... }
  }
}

在任何构建脚本中,都有一种简单的方法来以类型安全和IDE友好的方式访问元素

// build.gradle.kts
plugins {
  id("my.plugin")
}

myExtension {
  namedContainer.anElement { // auto generated accessor
  }
}

相关问题