Reputation: 1030
I am trying to use Groovy's Meta Programming, to dynamically read data from closure. Below is the example:
class MyClass {
static def metadata1 = {
metadataA(key1: 'value1', key2: "value2")
metadataB(key1: ['value1', 'value2'], key2: 78978)
}
static def metadata2 = {
metadataA(key1: 'value11', key2: "value21")
metadataB(key1: ['value11', 'value21'], key2: 78958)
}
static void main(def args) {
new MyClass().setup("metadata1")
new MyClass().setup("metadata2")
}
def setup(fieldName) {
try {
Field metaField = this.class.getDeclaredField(fieldName)
if (metaField != null) {
metaField.setAccessible(true)
def metaFieldVal = metaField.get(null)
if (metaFieldVal != null) {
metaFieldVal.delegate = this
metaFieldVal() // It will call closure metadata1 or metadata2
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace()
}
}
def methodMissing(String key, args) {
println(key) // metadataA
println(args) // [[key1:value1, key2:value2]]
//println(getNameofCalleeClosure()) //metadata1
}
}
In overridden methodMissing I am not able to identify field name of callee closure, here in case i.e. metadata1, metadata2. Is there any way in Groovy to get callee closure name for identification from where it is called?
Upvotes: 1
Views: 79
Reputation: 42272
There is no such thing like name of caller closure. In your example, in method setup(fieldName)
you search for a closure stored as a class field, and when you find the closure you execute it with metaFieldVal()
. There is no connection between field name metadata1
and the closure executed as metaFieldVal()
. Actually this setup(fieldName)
knows that this closure is stored as a class field, but closure itself is not aware of it.
If you want to get metadata1
or metadata2
field names inside methodMissing()
you have to simply pass it as this non-existing method parameter. Something like this:
class MyClass {
static def metadata1 = {
metadataA("metadata1", [key1: 'value1', key2: "value2"])
metadataB("metadata1", [key1: ['value1', 'value2'], key2: 78978])
}
static def metadata2 = {
metadataA("metadata2", [key1: 'value11', key2: "value21"])
metadataB("metadata2", [key1: ['value11', 'value21'], key2: 78958])
}
static void main(def args) {
new MyClass().setup("metadata1")
new MyClass().setup("metadata2")
}
def setup(fieldName) {
try {
Field metaField = this.class.getDeclaredField(fieldName)
if (metaField != null) {
metaField.setAccessible(true)
def metaFieldVal = metaField.get(null)
if (metaFieldVal != null) {
metaFieldVal.delegate = this
metaFieldVal() // It will call closure metadata1 or metadata2
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace()
}
}
def methodMissing(String key, args) {
println(key) // metadataA
println(args) // [metadata1, [key1:value1, key2:value2]]
}
}
It is also worth mentioning that executing missing method like this:
static def metadata1 = {
metadataA(this, [key1: 'value1', key2: "value2"])
metadataB(this, [key1: ['value1', 'value2'], key2: 78978])
}
produces:
[class MyClass, [key1:value1, key2:value2]]
and passing a field metadata1
like this:
static def metadata1 = {
metadataA(metadata1, [key1: 'value1', key2: "value2"])
metadataB(metadata1, [key1: ['value1', 'value2'], key2: 78978])
}
will produce:
[MyClass$__clinit__closure1@50d0686, [key1:value1, key2:value2]]
because closure has no name.
Upvotes: 1