Gradle:如何将列表从配置关闭映射到扩展设置

Gradle: How to map Lists from configuration-closure to extension settings

我有这个(有效的)代码,它是从 gradle 文档

扩展而来的

https://docs.gradle.org/4.10.3/userguide/custom_plugins.html#sec:implementing_a_dsl

class User {
    String name
}


class Group {
    User user
}

class GreetingPluginExtension {
    String message
    final Group group

    @javax.inject.Inject
    GreetingPluginExtension(ObjectFactory objectFactory) {
        group = objectFactory.newInstance(Group)
        group.user = objectFactory.newInstance(User)
    }

    void group(Action<? super Group> action) {
        action.execute(group)
    }

    void user(Action<? super User> action) {
        action.execute(group.user)
    }
}

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        // Create the extension, passing in an ObjectFactory for it to use
        def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
        project.task('hello') {
            doLast {
                    println "${extension.message} from ${extension.group.user.name}"
            }
        }
    }
}

配置闭包如下所示:

greeting {
    message = 'Hello'
    group {
        user {
            name = 'tom'
        }
    }
}

但我想要一个我尝试过的用户列表:

class User {
    String name
}


class Group {
    ArrayList<User> users
}

class GreetingPluginExtension {
    String message
    final Group group

    @javax.inject.Inject
    GreetingPluginExtension(ObjectFactory objectFactory) {
        // Create a Person instance
        group = objectFactory.newInstance(Group)
        group.users = []
    }

    void group(Action<? super Group> action) {
        action.execute(group)
    }

    void users(Action<? super ArrayList<User>> action) {
        action.execute(group.users)
    }
}

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        // Create the extension, passing in an ObjectFactory for it to use
        def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
        project.task('hello') {
            doLast {
                extension.group.users.each {

                    println "${extension.message} from ${it.name}"
                }

            }
        }
    }
}

关闭后:

greeting {
    message = 'Hello'
    group {
        users = [
                {name = 'tom'} ,
                {name = 'tim'}
        ]
    }
}

我的输出如下:

Hello from myProjectName
Hello from myProjectName

这不是预期的输出,而是 rootProject.name 输出具有正确数量的元素,但未引用给用户。 我怎样才能解决这个问题?我还希望了解有关将嵌套对象(和列表)映射到扩展设置的其他方法的信息。

问候汤姆

我认为以下稍作修改的版本符合您的预期:

apply plugin: GreetingPlugin

greeting {
    message = 'Hello'
    group {
      user(name: 'tom')
      user(name: 'tim')
    }
}


class User {
    String name
}

class Group {
    ArrayList<User> users = []

    def user(props) {
      users << new User(props)
    }
}

class GreetingPluginExtension {
    String message
    final Group group

    @javax.inject.Inject
    GreetingPluginExtension(ObjectFactory objectFactory) {
        // Create a Person instance
        group = objectFactory.newInstance(Group)
    }

    void group(Action<? super Group> action) {
        action.execute(group)
    }
}

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        // Create the extension, passing in an ObjectFactory for it to use
        def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
        project.task('hello') {
            doLast {
                extension.group.users.each {
                    println "${extension.message} from ${it.name}"
                }

            }
        }
    }
}

当运行时,它打印:

~> gradle hello

> Task :hello
Hello from tom
Hello from tim

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

请注意,我已经删除了方法:

void users(Action<? super ArrayList<User>> action)

因为上面的工作不需要它。我也稍微改变了 dsl。我实际上认为更改后的 dsl 看起来更具可读性和惯用性,但这当然是个人喜好问题。

另请注意,如果您想向用户发送更多属性(比如 email),您可以在不修改脚手架代码的情况下执行此操作,即:

greeting {
    message = 'Hello'
    group {
      user(name: 'tom', email: 'tom@wonderland.org')
      user(name: 'tim', email: 'tim@wonderland.org')
    }
}
class User {
    String name
    String email
}

如果您专门寻找如何为集合工作创建双重嵌套配置闭包,这并不能解决您的问题,但它确实为您提供了一种相当干净的方法来完成构建脚本的预期目的。