将对象实例添加到Gradle插件扩展中

12

我有一个类似下面插件的东西,有一个外部命名空间,在其中有一个对象的单一“具体”实例(mother)和另一个集合(children)。

family {
  mother {
      firstname = 'John'
      lastname  = 'Cleese'
  }
  children {
      son {
        firstName = 'John'
        lastName  = 'Cleese'
      }
      daughter {
        firstName = 'Jane'
        lastName  = 'Cleese'
      }
  }
}

我能够根据各种示例添加集合对象并读取变量,但不确定如何添加具体实例。


我该如何在扩展对象上定义它?

以下是显示问题的代码 - 我想将mother作为插件中的单个实例添加。

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.*

class Person
{
  final String name
  String firstName
  String lastName
  Person(String name) { this.name = name }
}

class FamilyExtension {

  final NamedDomainObjectContainer<Person> children
  Person mother
  Person father

  FamilyExtension(children) {
    this.children = children
  }

  def children(Closure closure) {
    children.configure(closure)
  }
}

class FamilyPlugin implements Plugin<Project> {

  void apply(Project project) {
    project.task('sayHello', type: DefaultTask) << { 
      println(
        "Hello ${project.family.children["son"].firstName} " +
        "and hello ${project.family.children["daughter"].firstName} ")
    }

    def children  = project.container(Person)

    project.extensions.create("family", FamilyExtension, children)
  }
}
apply plugin: FamilyPlugin

family {
  // How do I add support for this?
  // mother {
  //     firstname = 'John'
  //     lastname  = 'Cleese'
  // }
  children {
      son {
        firstName = 'John'
        lastName  = 'Cleese'
      }
      daughter {
        firstName = 'Jane'
        lastName  = 'Cleese'
      }
  }
}

不确定您想要实现什么。是在母亲上添加设置“firstname”和“lastname”的支持,还是只有一个单一的母亲? - Opal
我想在单个母对象上设置名称值,但更普遍地说,我想了解DSL中对象容器和“普通”对象的混合使用方式。 - LK__
我也没有找到任何同时使用这两个的示例项目,也不知道如何在不使用configure(closure)的情况下在扩展上设置对象。 - LK__
2个回答

4
我遇到了和你一样的问题,但我想出了如何在我的案例中创建“母亲”,而不是“孩子”的方法。我使用嵌套扩展对象来实现这一点。
以下是我是如何做到的(我的代码是纯Java的,因此您可能需要进行一些更改才能在Groovy中完成 - 我对Groovy非常陌生,所以不确定需要更改什么):
当您在插件中添加扩展时,该类将自动支持ExtensionAware接口,因此可以向其添加扩展。在您的FamilyExtension构造函数中,首先将该类转换为ExtensionAware,然后添加一个新扩展:
public FamilyExtension(NamedDomainObjectContainer<Person> children) {
    ((ExtensionAware) this).getExtensions().create("mother",Person.class);
    this.children = children;
}

这只允许一个单一的母亲,就像你所声明的那样。 但是请注意,它不会强制要求只有一个母亲,因为你可以添加任意多个母亲,但是任何后续的声明都会改变该单个实例上的值,因此实际上只有一个母亲。 如果母亲没有被声明,您也可能会得到空值,因此需要测试它(一些演示说可能会发生这种情况,但在我的实验中似乎并不会发生)。

要获取您的母亲对象,只需将您的扩展强制转换为ExtensionAware,并从中检索Person类,就像您从项目中获取家族扩展一样。

FamilyExtension fext = project.getExtensions().findByType(Person.class)
Person mother = (Person) ((ExtensionAware) fext).getExtensions().findByName("mother")

编辑: 另一种方法是在您的扩展对象上定义一个接受闭包的函数,并使闭包委托给一个新的母对象。然后,您可以使用布尔标志来强制仅使用一个母亲对象。

private boolean mother_defined = false;
private Person mother_value = null;  // or Person mother = new Person()

public void mother(Closure<?> motherdef) {
    if (mother_defined) {throw new Exception("Only one mother allowed");}
    mother_value = new Person();
    motherdef.setDelegate(mother);
    motherdef.call();
    mother_defined = true;
}

这是一个非常有用的答案。如果您为每个代码块包含文件名,那将不会让人猜测,我会更喜欢它,但是最终我还是能够搞清楚。这是最奇怪的部分:((ExtensionAware) this)。我的第一个直觉是使用接受Closure的方法。 - Jonathan Komar

4

好的,要给family添加mother闭包,您需要将以下代码添加到FamilyExtension类中。

Person mother(Closure closure) {
   mother = new Person()
   project.configure(mother, closure)
   return mother
}

如果你想在FamilyPlugin.apply方法中添加children扩展到家庭中,可以添加以下代码:

project.extensions.create("family", FamilyExtension, instantiator, project)
project.family.extensions.create("children", FamilyExtension.Children, project)

然后您添加
void son(Closure closure) {
    Person son = new Person()
    project.configure(son, closure)
    children.add(son)
}

能够将son闭包添加到children中。

要查看完整项目和更详细的说明,请访问Github项目https://github.com/andriipanasiuk/family-gradle-plugin


似乎这是DSL扩展开发的绝佳示例,但是在Kotlin中实现这个项目呢?我们能否在不使用Groovy特定的Closure类型的情况下完成这个任务? - Yevhenii Nadtochii
你知道是否可能为嵌套闭包使用未预定义的名称吗?例如,如果我想要像myPlugin { flavors { name_of_project_module_flavors { /* 这里是名称的列表 */ } } } 这样的东西。 - sandrstar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接