in format "${class-name}(${property-name}:${property-value}, …)".
First, I will give you an example in Java for comparison.
Java version:
----
class AnObject {
// property definitions
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getName()).append("(");
try {
PropertyDescriptor[] pds =
Introspector.getBeanInfo(this.getClass()).getPropertyDescriptors();
for (int i = 0, c = 0, sz = pds.length; i < sz; i++) {
PropertyDescriptor pd = pds[i];
if (!"class".equals(pd.getDisplayName())) {
Object v = pd.getReadMethod().invoke(this);
if (c != 0) {
sb.append(", ");
}
sb.append(pd.getDisplayName()).append(":").append(v);
c++;
}
}
} catch (Exception e) {}
sb.append(")");
return sb.toString();
}
}
----
I shortened the code as much as possible without losing readability, but it requires you to hit keys about 800 times.
Let’s rewrite this in Groovy.
Groovy (using java.beans) version:
----
class AnObject {
// property definitions
String toString() {
"""${ this.class.name }(${
try {
Introspector.getBeanInfo(this.class).propertyDescriptors
.findAll{ pd ->
"class" != pd.displayName && "metaClass" != pd.displayName }
.collect{ pd ->
"${ pd.displayName }:${ pd.readMethod.invoke(this) }" }
.join(", ")
} catch(e) {}
})"""
}
}
----
Now it's much shorter.
You can make it a little more shorter by using MetaClass.
Groovy (using MetaClass) version:
----
class AnObject {
// property definitions
String toString() {
"""${ this.class.name }(${
properties
.findAll{ p -> "metaClass" != p.key && "class" != p.key }
.collect{ p -> "${ p.key }:${ p.value }" }
.join(", ")
})"""
}
}
----
* MetaClass does not keep order of property definitions because it has metadata of properties in hash map.
Actually you can also make it just 1 line by using dump() method If you won't need a custom format.
Groovy (using dump() method) version:
Groovy (using dump() method) version:
----
class AnObject {
// property definitions
String toString() {
dump()
}
}
----
In this case, the format will be "<${class-name}@${hash-code} ${property-name}=${property-value} ...>".
MetaClass and dump() method are also provided by the GDK that extends the JDK.
MetaClass and dump() method are also provided by the GDK that extends the JDK.
It'd be great to see this one applied at the beginning of a grails application (in BootStrap maybe) to all domain classes where toString has not been overriden. This way whenever a new class is being created it will always have a proper toString method right out of the box.
ReplyDeleteBtw. this will be obsolete starting with Groovy 1.8 where the @ToString annotation will be available taking care of the problem.
Thank you Matthias, I will try Groovy 1.8.
ReplyDelete