closure.resolveStrategy = Closure.DELEGATE_FIRST descriptiom - unix1998/technical_notes GitHub Wiki
In Groovy, closures have a property called resolveStrategy
which determines how methods and properties within the closure are resolved. The resolveStrategy
affects the delegation behavior of closures, i.e., how the closure resolves method calls and property accesses. There are several strategies available:
OWNER_FIRST
(default): The closure first attempts to resolve methods and properties in its owner (the enclosing class or closure). If not found, it then looks in its delegate.DELEGATE_FIRST
: The closure first attempts to resolve methods and properties in its delegate. If not found, it then looks in its owner.OWNER_ONLY
: The closure only resolves methods and properties in its owner, ignoring the delegate.DELEGATE_ONLY
: The closure only resolves methods and properties in its delegate, ignoring the owner.TO_SELF
: The closure resolves methods and properties within itself (typically used with nested closures).
Closure.DELEGATE_FIRST
Explanation of When you set closure.resolveStrategy = Closure.DELEGATE_FIRST
, it means that the closure will first attempt to resolve any method calls or property accesses on the delegate object. If the method or property is not found on the delegate, it will then fall back to the owner.
This is particularly useful in DSLs where you want the closure to apply settings to a specific object (the delegate), even though the closure itself might be defined in another context (the owner).
Example
Here’s a simple example to illustrate the different resolve strategies:
class Example {
String name = 'Owner'
def run() {
def closure = {
println "Closure name: ${name}"
}
// Setting delegate
def delegate = new Delegate()
closure.delegate = delegate
// Using different resolve strategies
println 'OWNER_FIRST (default)'
closure.resolveStrategy = Closure.OWNER_FIRST
closure() // Output: Closure name: Owner
println 'DELEGATE_FIRST'
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure() // Output: Closure name: Delegate
println 'OWNER_ONLY'
closure.resolveStrategy = Closure.OWNER_ONLY
closure() // Output: Closure name: Owner
println 'DELEGATE_ONLY'
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure() // Output: Closure name: Delegate
println 'TO_SELF'
closure.resolveStrategy = Closure.TO_SELF
closure() // Output: Closure name: Owner (since name is not found in the closure itself)
}
}
class Delegate {
String name = 'Delegate'
}
new Example().run()
Using in Your Context
In your Groovy DSL example, you want the closure to apply settings to the WebServer
instance. Therefore, using Closure.DELEGATE_FIRST
ensures that properties and methods defined on WebServer
are resolved first within the closure:
import org.example.WebServer
def call(Closure closure) {
def server = new WebServer()
closure.delegate = server
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure()
server.start()
}
In this setup, when you call methods like name
, port
, and route
within the closure, Groovy will first try to resolve these methods on the WebServer
instance (delegate
) before looking at the enclosing context (owner
). This makes it easier to build DSLs where the closure configuration should apply to a specific object.
Summary of Strategies
OWNER_FIRST
(default): Looks in the owner first, then delegate.DELEGATE_FIRST
: Looks in the delegate first, then owner.OWNER_ONLY
: Only looks in the owner.DELEGATE_ONLY
: Only looks in the delegate.TO_SELF
: Looks within the closure itself.
These strategies allow you to control how Groovy closures resolve methods and properties, which is particularly useful in building flexible and intuitive DSLs.