More on gradle closures
satya - 7/25/2018, 9:46:11 AM
There are lots of them, these closures in Gradle
There are closures on a project object that are documented in the API for a project
it is important to know what the delegate for a Closure is
Closure uses the delegate to resolve methods and properties
Closures in Gradle are used often to call methods on its delegate to configure that delegate
when a closure on a particular task is used, you are configuring the properties of that task to change its behavior
when you use a closure on a maven repository you are calling maven repository objects properties to add URLs.
satya - 7/25/2018, 9:47:37 AM
Consider this
buildscript {
repositories {
maven { url = "some-url" }
}
}
satya - 7/25/2018, 10:03:21 AM
Explanation
1. project defines a method with closure called buildscript. Passes ScriptHandler as the delegate
2. So ScriptHandler has a method repositories() that takes a closure. This closure uses RepoistoryHandler as the delegate.
3. maven is a method on RepositoryHandler with a closure. Documentation says it passes a Maven handler as a "parameter". Not a delegate.
4. However it appears as if it is also passed as a delegate
5. maven handler has a get/set property setUrl(url) to set the url(s) //i think
satya - 7/25/2018, 10:03:37 AM
groovy maven url property
groovy maven url property
satya - 7/25/2018, 10:03:54 AM
this, delegate, it, owner in groovy closures
this, delegate, it, owner in groovy closures
satya - 7/25/2018, 10:05:01 AM
You can do this in any closure
buildscript {
repositories {
maven {
url = "some-url"
println this
println it
println delegate
println owner
}
}
}
satya - 7/25/2018, 10:07:07 AM
Owner, delegate, this is explained here
satya - 7/25/2018, 10:11:49 AM
DefaultArtifactMavenRepository.groovy source code
DefaultArtifactMavenRepository.groovy source code
Search for: DefaultArtifactMavenRepository.groovy source code
satya - 7/25/2018, 10:20:25 AM
Odd, how can you add multiple urls for a single URL property in maven repository of Gradle?
Odd, how can you add multiple urls for a single URL property in maven repository of Gradle?
satya - 7/25/2018, 10:22:50 AM
Source code is correct. URL is a single value field.
Source code is correct. URL is a single value field.
satya - 7/25/2018, 10:23:13 AM
So this is wrong
repositories {
mavenCentral()
maven {
url "http://maven.springframework.org/release"
url "http://maven.restlet.org"
}
}
satya - 7/25/2018, 10:23:30 AM
Correct way
repositories {
maven { url "http://maven.springframework.org/release" }
maven { url "https://maven.fabric.io/public" }
}
satya - 7/25/2018, 10:27:16 AM
Because
if you see the "maven" method on the repositories handler it says this closure will "add and configure". Means each line or method call is an add of a new repo of maven!
That makes sense
satya - 8/16/2018, 12:23:30 PM
In understanding this further you will need a link to the nature of RepositoryHandler
In understanding this further you will need a link to the nature of RepositoryHandler
satya - 8/16/2018, 12:40:20 PM
RepositoryHandler is a sub class of ArtifactRepositoryContainer
RepositoryHandler is a sub class of ArtifactRepositoryContainer
satya - 8/16/2018, 12:40:39 PM
What is a ResolverContainer in Gradle?
What is a ResolverContainer in Gradle?
satya - 8/16/2018, 12:44:43 PM
RepositoryHandler
It is a collection of ArtifactRepositories
RepositoryHandler has a number of methods to add specific repositories
Its base calass ArtifactRepositoryContainer and its super classes can be used to retrieve the individual repositories
satya - 8/16/2018, 2:42:38 PM
Basic explanation of closure objects
this - usual this object in java
true even if the closure is a nested closure
owner - The parent object of the current clsoure
may be same as this for direct closures
will differ for inner closure
for an inner closure the the it is
the previous closure.
delegate - An external object acts like an owner
variables are scoped against the delegate as well
By default, delegate is set to owner
satya - 8/16/2018, 2:44:08 PM
Note that delegate is set and hence an object
Note that delegate is set and hence an object
satya - 8/16/2018, 2:44:23 PM
Consider these classes
class Person {
String name
}
class Thing {
String name
}
satya - 8/16/2018, 2:45:17 PM
Objects out of those
def p = new Person(name: 'Norman')
def t = new Thing(name: 'Teapot')
Also notice the auto named arg constructors.
satya - 8/16/2018, 2:47:57 PM
Define a closure
//Notice name is an unresolved variable
def cl = { name.toUpperCase() }
//Set the delegate to be "p" from above
cl.delegate = p
assert cl() == 'NORMAN'
//Set the delegate to be "t" from above
cl.delegate = t
assert cl() == 'IGOR'
satya - 8/16/2018, 2:50:06 PM
Closure.resolveStrategy can be set to
Closure.OWNER_FIRST is the default strategy. If a property/method exists on the owner, then it will be called on the owner. If not, then the delegate is used.
Closure.DELEGATE_FIRST reverses the logic: the delegate is used first, then the owner
Closure.OWNER_ONLY will only resolve the property/method lookup on the owner: the delegate will be ignored.
Closure.DELEGATE_ONLY will only resolve the property/method lookup on the delegate: the owner will be ignored.
Closure.TO_SELF can be used by developers who need advanced meta-programming techniques and wish to implement a custom resolution strategy: the resolution will not be made on the owner or the delegate but only on the closure class itself. It makes only sense to use this if you implement your own subclass of Closure.
satya - 8/16/2018, 2:54:21 PM
It the implicit parameter
When a closure does not explicitly define a parameter list (using ->), a closure always defines an implicit parameter, named it.
satya - 8/16/2018, 2:54:43 PM
Sample
def greeting = { "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'
satya - 8/16/2018, 2:55:47 PM
So in the end in your closure it is useful to do this to understand that closure
buildscript {
repositories {
maven {
url = "some-url"
println this
println it
println delegate
println owner
}
}
}
satya - 8/16/2018, 2:56:51 PM
In Java lambda expressions are instances of single method interfaces with inner class semantics
In Java lambda expressions are instances of single method interfaces with inner class semantics
satya - 8/16/2018, 2:57:09 PM
In Groovy closures are instances of Closure class with delegation capability
In Groovy closures are instances of Closure class with delegation capability
satya - 8/16/2018, 3:05:39 PM
So lets read this code again
//So this is wrong
repositories {
mavenCentral()
maven {
url "http://maven.springframework.org/release"
url "http://maven.restlet.org"
}
}
//Correct way
repositories {
maven { url "http://maven.springframework.org/release" }
maven { url "https://maven.fabric.io/public" }
}
satya - 8/16/2018, 3:08:12 PM
Explanation
Remember, Each child of respositories is "A REPOSITORY".
So mavenCentrl() is a repo.
maven (with a url) is ONE Repo
maven IS NOT a collection of URLs, in other words maven() is not a collection of maven repositories.
The underlying repository MavenArtifactRespoistory() has a method setURL() which sets the URL. Calling it again will overr write the previous one.
So it all depends on how the underlying java classes and their methods are implemented.
satya - 8/16/2018, 3:59:50 PM
Consider this
repositories {
flatDir name: 'libs', dirs: "$projectDir/libs"
flatDir dirs: ["$projectDir/libs1", "$projectDir/libs2"]
}
satya - 8/16/2018, 4:01:25 PM
Exaplanation
There are 2 repos here
Both of type flatDir, or just a directory to look for assets
First Flat directory
It is called "libs"
it has a root directory specified
Second Flat Directory
it has no name
it is a list of directories
satya - 8/16/2018, 4:02:14 PM
It is better read as
There are 2 repos here
Both of type flatDir, or just a directory to look for assets
First Flat directory
It is called "libs"
it has a root directory specified
Second Flat Directory
it has no name
it is a list of directories
satya - 8/16/2018, 4:03:03 PM
This is facilitated by flatDir() method signature on RepositoryHandler
FlatDirectoryArtifactRepository flatDir(Map<String, ?> args)
satya - 8/16/2018, 4:05:58 PM
Explanation
It is a map that is the input
It is really an associate array
Meaning it should have been an object definition like
FileDirSpec
name
List<String> dirs;
Instead this is represented as a generic map
This map can have only 2 keys
name - A string
dirs - A string, or a list of strings
satya - 8/16/2018, 4:07:45 PM
So I can read this as
repositories {
flatDir name: 'libs', dirs: "$projectDir/libs"
flatDir dirs: ["$projectDir/libs1", "$projectDir/libs2"]
}
//First one
map1.add("name", "libs")
map1.add("dirs","$projectDir/libs");
flatDir(map1)
//Similarly second one
satya - 8/16/2018, 4:08:30 PM
See this to understand named arguments to constructors and methods
See this to understand named arguments to constructors and methods