karfai karfai - 11 days ago 6
Groovy Question

How to implement this 'dynamic block' in Gradle?

I am new to gradle. So let straight to the point. I want to implement the block as below. Note that the libraries is dynamic, and available for other developers to add on for the needed libraries.

libraries {
slf4j 'org.slf4j:slf4j-api:1.7.21'
junit 'junit:junit:4.12'
}


So that I can call them out like this.

dependencies {
compile libraries.slf4j
testCompile libraries.junit
}


I am not sure how to make it. But I found some related solution from here. As shown below:

apply plugin: GreetingPlugin

greeting {
message 'Hi'
greeter 'Gradle'
}

class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("greeting", GreetingPluginExtension)
project.task('hello') {
doLast {
println "${project.greeting.message} from ${project.greeting.greeter}"
}
}
}
}

class GreetingPluginExtension {
String message
String greeter
}


The problem is as I add on to the
greeting
block, I need to declare them in
GreetingPluginExtension
as well. Any idea how to make it such that only update on
greeting
block?

Answer

What you need to do is to utilize groovy meta programming. Below you can find just a sample, however fully functional.

apply plugin: LibrariesPlugin

libraries {
    slf4j 'org.slf4j:slf4j-api:1.7.21'
    junit 'junit:junit:4.12'
}

class LibrariesPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create("libraries", LibrariesPluginExtension)
        project.task('printLib') {
            doLast {
                println "$project.libraries.slf4j"
                println "$project.libraries.junit"

                project.libraries.each {
                    println "$it.key -> $it.value"
                }
            }
        }
    }
}

class LibrariesPluginExtension {

    Map libraries = [:]

    def methodMissing(String name, args) {
        // TODO you need to do some arg checking here
        libraries[name] = args[0]
    }

    def propertyMissing(String name) {
        // TODO same here
        libraries[name]
    }

    Iterator iterator() {
        libraries.iterator()
    }
}
Comments