5

I have trouble understanding the groovy syntax in gradle.

If named parameters (in groovy) are using the : suffix, then I assume that the code apply plugin: 'java' means to call the function apply(plugin = 'java'). This is strange because the function apply is not even defined. The following gives me an error in my gradle script:

println apply.getClass()
> Could not get unknown property 'apply' for root project 'Simple' of type 
org.gradle.api.Project.

So what is apply and where is it defined? Why doesn't the code above just print the class of the apply element?

And one other thing that is strange to me is the following:

dependencies {
    compile 'org.slf4j:slf4j-api:1.7.12'
    testCompile 'junit:junit:4.12'
}

The syntax suggests that the code wrapped in {} is a closure, but what are the compile and testCompile elements? If it was a closure, then the code above would just return 'junit:junit:4.12' as a string and the rest should fail to compile. It looks like it's more a definition of a map. But again, if the code above is data, then I should be able to enter it at the groovysh shell.

groovy:000> dependencies {
        compile 'org.slf4j:slf4j-api:1.7.12'
        testCompile 'junit:junit:4.12'
    }
groovy:001> groovy:002> groovy:003> ERROR groovy.lang.MissingMethodException:
No signature of method: groovysh_evaluate.dependencies() is applicable for argument types: (groovysh_evaluate$_run_closure1) values: [groovysh_evaluate$_run_closure1@b7c4869]

This is confusing to me. I thought that gradle scripts are just groovy scripts, but it seems that the gradle DSL adds element to the groovy language. A groovy clojure becomes a map, a function call with named parameters becomes something different.

Can someone enlighten me on this groovy DSL ;)

shaft
  • 2,147
  • 2
  • 22
  • 38
  • Just wondering, should that say a "groovy closure"? Just asking because I searched for "Clojure" questions and this came up. – Carcigenicate May 02 '17 at 22:36
  • Possible duplicate of [Understanding the groovy syntax in a gradle task definition](https://stackoverflow.com/questions/27584463/understanding-the-groovy-syntax-in-a-gradle-task-definition) – tkruse Jan 29 '18 at 07:46

2 Answers2

3
plugin: 'java' 

is a groovy map. See the Project.apply() documentation and the explanation for this syntax in the groovy documentation.

Regarding dependencies, see DependencyHandler.

Groovy is a very dynamic language, where you can actually call non-declared methods and have a handler do something based on the called method name. AFAIK, that's the trick used here. See the source code.

I'm not a groovy developer, and although I find the DSL elegant, I also find it confusing at times, because I find it hard to link some parts of the DSL to concrete methods in the documentation. But you end up understanding it and getting used to it.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Good points. Then it makes that `apply` cannot be resolved since it's just intercepted by an extension. Wow, there's lot of new things here to learn in groovy. I am currently trying to get into the gradle build system, but it looks like you need to have solid understanding of groovy to really grasp it. But beside that, but DSL is really nice ;) – shaft Apr 29 '17 at 22:18
  • @shaft the Groovy can be confusing and magical at times. There is also [gradle-script-kotlin](https://github.com/gradle/gradle-script-kotlin), which allows for build scripts to be written in Kotlin instead of Groovy. It is moving nicely towards `1.0` and in my opinion makes build scripts a lot easier to understand. – mkobit Apr 30 '17 at 04:33
2

compile 'org.slf4j:slf4j-api:1.7.12' is not a map, it's a method invocation. In Groovy you can omit brackets, so the call is equivalent to

compile( 'org.slf4j:slf4j-api:1.7.12' ) 

Also such methods in Gradle can take the second argument:

compile( 'org.slf4j:slf4j-api:1.7.12' ){ exclude module:'log4j' }

In this case, the module:'log4j' is a map with omitted square brackets, and the call can be rewritten as

compile( 'org.slf4j:slf4j-api:1.7.12' ){ exclude( [module:'log4j'] ) }
injecteer
  • 20,038
  • 4
  • 45
  • 89
  • Reads like data but is a method call, I guess it takes a while to get used to it ;) . But Thanks for the explanation. Groovy seems really powerful for creating DSL's. – shaft Apr 29 '17 at 22:22