Music, software, life… and stuff.
[ Twitter ] [ GitHub ] [ Linked In ]
I just came across some Groovy code that essentially looks like this…
def installConstructor(Class clazz) {
clazz.metaClass.constructor = { Map params ->
def instance = clazz.newInstance()
// do some stuff with params
instance
}
}
Looks innocent at first right?
Consider this…
class Parent {}
class Child extends Parent { String name }
ExpandoMetaClass.enableGlobally() // enable metaclass inheritance
installConstructor(Parent)
def c = new Child(name: "LD")
The issue here is that c is not going to be what you expect. You are going to get back an instance of Parent from this constructor call because our newly added constructor added to Parent is hardcoded to return Parent instances.
The fix is easy…
def installConstructor(Class clazz) {
clazz.metaClass.constructor = { Map params ->
def instance = delegate.newInstance()
// do some stuff with params
instance
}
}
For a dynamic constructor implementation, delegate refers to the actual target class of the construction. So unless you are doing some really wild stuff and deliberately returning objects of a different class, you always want to use delegate as the target class.
Posted: Feb 21st, 2010 @ 12:46 pm