I'm using the following code with builder:
Closure getObject = { String oType ->
return {
type oType
format 'int32'
}
}
def yaml = new YamlBuilder()
yaml{
string 'value'
object1{
Closure type = getObject 'integer'
type.delegate = delegate
type()
}
object2{
Closure type = getObject 'long'
type.delegate = delegate
type()
}
}
println yaml.toString()
The code works as expected and produces correct yaml.
Now I want to remove repeating lines of code and introduced the inflate()
method:
def inflate( Closure closure, delegate ) {
closure.delegate = delegate
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure()
}
so that my DSL gets more compact:
yaml{
string 'value'
object1{
inflate getObject( 'integer' ), delegate
}
object2{
inflate getObject( 'long' ), delegate
}
}
This led to the SOE:
java.lang.StackOverflowError
at Script1$_run_closure1$_closure3.doCall(Script1.groovy:5)
at Script1$_run_closure1$_closure3.doCall(Script1.groovy)
What am I missing?
The script can be played with on appSpot
It turns out, that instead of a method a Closure should be used.
In this case the closure nesting and reuse is not a problem any more:
import groovy.yaml.YamlBuilder
Closure inflate = { Closure closure, del ->
closure.delegate = del
closure()
}
Closure getObject = { String oType ->
return {
type oType
format 'int32'
}
}
Closure getNestedObject = {
return {
type 'object'
nested{
inflate getObject( 'nested' ), delegate
}
}
}
def yaml = new YamlBuilder()
yaml{
string 'value'
object1{
inflate getObject( 'integer' ), delegate
}
object2{
inflate getNestedObject(), delegate
}
}
println yaml.toString()
prints
---
object1:
type: "integer"
format: "int32"
object2:
type: "object"
nested:
type: "nested"
format: "int32"
The runnable code is here