Ran into this while doing a refactor. Calls to getProperties() were causing our CPU usage to spike. What we discovered is that if you have a getter without an associated attribute, when you make a call to getProperties() that getter is called over 1000 times. The fix/workaround is obvious and we know it has something to do with metaprogramming but why is this happening (what point in the groovy source)? See groovy script code below:
class tester {
int count = 0
public getVar() {
println count++ + " getVar() called!"
return var
}
}
def t = new tester()
t.getProperties()
println "done!"
You should see getVar() called over 1000 times. 1068 to be exact for us.
The question has probably already been answered in the comments but I dug a little deeper to also answer the "what point in the groovy source" part.
When you call getProperties()
on the instance of tester
Groovy will do its magic and finally call DefaultGroovyMethods#getProperties(Object)
which (in Groovy 2.4.7) looks like this:
public static Map getProperties(Object self) {
List<PropertyValue> metaProps = getMetaPropertyValues(self); // 1
Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size());
for (PropertyValue mp : metaProps) {
try {
props.put(mp.getName(), mp.getValue()); // 2
} catch (Exception e) {
LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
}
}
return props;
}
First, Groovy determines the meta properties of the given object (see 1). This will return three properties:
var
: getter only (getVar()
), no setter, no fieldclass
: getter only (inherited from Object
), no setter, no fieldcount
: getter, setter (both generated by Groovy) and fieldYou can easily verify this by calling t.getMetaPropertyValues()
.
Next, Groovy tries to get the current value of each property and puts it in a map (see 2). When it reaches var
, it remembers that var
has a getter (namely getVar()
) and calls it. getVar()
however, returns var
again. For Groovy, this is the exact same property as determined in the first step. Once again, it calls its getter getVar()
and the endless loop begins.
At some point, depending on the JVM, this results in a StackOverflowError
, which is exactly what this site is all about :-D
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With