Search code examples
gradlekotlinclosuresgradle-kotlin-dsl

What is the difference between closureOf and delegateClosureOf in Gradle Kotlin DSL


The official doc says:

You may sometimes have to call Groovy methods that take Closure arguments from Kotlin code. For example, some third-party plugins written in Groovy expect closure arguments.

In order to provide a way to construct closures while preserving Kotlin’s strong typing, two helper methods exist:

  • closureOf<T> {}
  • delegateClosureOf<T> {}

Both methods are useful in different circumstances and depend upon the method you are passing the Closure instance into. Some plugins expect simple closures. In other cases, the plugin expects a delegate closure. There sometimes isn’t a good way to tell, from looking at the source code, which version to use. Usually, if you get a NullPointerException with closureOf<T> {}, using delegateClosureOf<T> {} will resolve the problem.

Well, I have nothing againgst try-fail-fix approach, but maybe there is a deterministic way to tell in advance which method to use and why?


Solution

  • but maybe there is a deterministic way to tell in advance which method to use

    Sure by simply examining the source code of the plugin you are configuring. For example, their Bintray plugin example is:

    bintray {
        pkg(closureOf<PackageConfig> {
            // Config for the package here
        })
    }
    

    If you were to examine the source, you'll find this: https://github.com/bintray/gradle-bintray-plugin/blob/master/src/main/groovy/com/jfrog/bintray/gradle/BintrayExtension.groovy#L35..L37

    def pkg(Closure closure) {
        ConfigureUtil.configure(closure, pkg)
    }
    

    That is a simple Closure so closureOf<T> {} would be appropriate here according to the docs.

    Now their other example is for the Gretty Plugin when configuring farms:

    farms {
        farm("OldCoreWar", delegateClosureOf<FarmExtension> {
            // Config for the war here
        })
    }
    

    If you examine the source, you'll find this: https://github.com/akhikhl/gretty/blob/master/libs/gretty-core/src/main/groovy/org/akhikhl/gretty/FarmsConfig.groovy#L23..L32

      void farm(String name = null, Closure closure) {
        if(name == null)
          name = ''
        def f = farmsMap_[name]
        if(f == null)
          f = farmsMap_[name] = createFarm()
        closure.delegate = f
        closure.resolveStrategy = Closure.DELEGATE_FIRST
        closure()
      }
    

    That's much more complex than the previous example and according to the docs, since this clearly expects delegate closure, then delegateClosureOf<T> {} would be the appropriate choice.