When you start nesting or delegating closures in Groovy, understanding how scope resolution works becomes crucial. In this tutorial, we’ll demystify the three key references inside a closure—this, owner, and delegate—and show you how to control them to build powerful DSLs and scripts.
Preparation
Make sure Groovy is installed. You can use:
- SDKMAN (Linux/macOS):
sdk install groovy
- Groovy Console for interactive editing:
groovyConsole
Online editors like TutorialsPoint Groovy Editor https://www.tutorialspoint.com/compilers/online-groovy-compiler.htm
Save code in ClosureScopeExample.groovy and run with groovy ClosureScopeExample.groovy.
What is this owner, and delegate?
- this
Points to the enclosing class or script instance where the closure is defined.
- owner
The immediate enclosing object of the closure—either the class/script or another closure if nested.
- delegate
A supplementary reference that you can set at runtime to redirect method/property resolution. By default, it’s the same as the owner.
Example: Default Resolution
class ScopeDemo {
def name = 'ScopeDemo'
def runDemo() {
def closure = {
println "this.name: ${this.name}"
println "owner.name: ${owner.name}"
println "delegate.name: ${delegate.name}"
}
closure()
}
}
new ScopeDemo().runDemo()
Output:
this.name: ScopeDemo
owner.name: ScopeDemo
delegate.name: ScopeDemo
Here, all three resolve to the ScopeDemo instance.
Nested Closures and owner
def outer = {
def inner = {
println "owner is outer? " + (owner == outer)
println "this is script? " + (this instanceof GroovyScript)
}
inner()
}
outer()
Output:
owner is outer? true
this is script? true
- owner of the inner closure is the outer closure.
- *his remains the script instance.
Changing the delegate and the Resolve Strategy
You can redirect method/property calls to a different object by changing the delegate and using resolve strategies:
class Person {
String name
}
def closure = {
println "Hello, $name!"
}
def p = new Person(name: 'Alice')
closure.delegate = p
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure() // Output: Hello, Alice!
- Closure.DELEGATE_FIRST tries the delegate before owner.
- Closure.OWNER_FIRST (default) tries the owner before delegate.
Practical DSL Example
Building a tiny HTML builder:
class HtmlBuilder {
def content = ''
def html(Closure cl) {
cl.delegate = this
cl.resolveStrategy = DELEGATE_FIRST
content += '<html>'
cl()
content += '</html>'
}
def body(Closure cl) {
content += '<body>'
cl.delegate = this
cl.resolveStrategy = DELEGATE_FIRST
cl()
content += '</body>'
}
def p(String text) {
content += "<p>${text}</p>"
}
}
def builder = new HtmlBuilder()
builder.html {
body {
p 'Hello, World!'
}
}
println builder.content
Output:
<html><body><p>Hello, World!</p></body></html>
Here delegate lets the closure call p directly on the builder.
Conclusion
Understanding this, owner, and delegate unlock Groovy’s full power for nested closures and custom DSLs. You now know how to:
- Identify each reference in different contexts
- Redirect resolution with delegate and resolveStrategy
- Build concise, readable DSLs
You can find the full source for this tutorial on our GitHub.
That just the basic. If you need more deep learning about Groovy and Grails you can take the following cheap course:
- Mastering Grails. A Comprehensive Grails Course.
- Groovy Scripting for Developers / Testers
- Introduction to JVM Languages Clojure, Kotlin, and Groovy
Thanks!