I would like to overwrite a dynamic property on a metaClass but it's not working as I would expect. Here is a simple example that demonstrate the problem. You can run it online at Groovy web console
class Bike {}
class Bell { def ring() { println("calling " + this) } }
def createNamespaces = {
return [ "bell": new Bell() ]
}
def resetNamespaces = { bike ->
// setting to null means 'set it to the default'
bike.metaClass = null
createNamespaces().each { name, namespace ->
println("setting " + namespace)
bike.metaClass."$name" = namespace
}
}
def bike= new Bike()
resetNamespaces(bike)
bike.bell.ring()
resetNamespaces(bike)
bike.bell.ring()
The result is:
setting Bell@14e9bd2b
calling Bell@14e9bd2b
setting Bell@948a7ad
calling Bell@14e9bd2b
So although I changed the property on the metaClass, calling it always returns the first object that was set. Is there some kind of caching?
When I just change the last part of the example to:
resetNamespaces(bike)
resetNamespaces(bike)
bike.bell.ring()
Then the result is as expected. That is, calling the property returns the object that was set on the metaClass as the last:
setting Bell@5b47e0c7
setting Bell@19f373a4
calling Bell@19f373a4
I even tried to set metaClass manually as follows
def resetNamespaces = { bike ->
def newMetaClass = new ExpandoMetaClass(Bike.class, true, true)
newMetaClass.initialize()
bike.metaClass = newMetaClass
...
}
But the result is still the same. So there must be some caching mechanism involved. I can't find anything about this behavior in the documentation.