Given bindgen is just method calls, it is fast.
This was not an explicit design goal, but instead a benefit that comes from the primary goal of using type-safe, compile-checked constructs.
Calling the expression parent.name 1,000,000 times gives the follow stats:
ognl cached: 1124535381ns
click proputil: 313962668ns
new binding: 238833707ns
existing binding: 23681850ns
static binding: 28652874ns
So, in a tight loop like rendering a table, bindgen is 97.5% faster than OGNL.
The test code:
public class BindgenPerfTest extends TestCase {
private static final int loops = 1000000;
public void testOgnlWithCachingByClickPropertyUtils() throws Exception {
Parent p = new Parent("p");
Child c = new Child(p, "c");
Map<String, String> context = new HashMap<String, String>
PropertyUtils.getValueOgnl(c, "parent.name", context); // Let it cache
long start = System.nanoTime();
for (int i = 0; i < BindgenPerfTest.loops; i++) {
Assert.assertEquals("p", PropertyUtils.getValueOgnl(c, "parent.name", context));
}
this.stop("ognl cached", start);
}
public void testClickPropertyUtils() {
Parent p = new Parent("p");
Child c = new Child(p, "c");
Map< ?> cache = new HashMap<String, String>
PropertyUtils.getValue(c, "parent.name", cache); // Let it cache
long start = System.nanoTime();
for (int i = 0; i < BindgenPerfTest.loops; i++) {
Assert.assertEquals("p", PropertyUtils.getValue(c, "parent.name", cache));
}
this.stop("click proputil", start);
}
public void testBindgenNewBindingEachTime() {
Parent p = new Parent("p");
Child c = new Child(p, "c");
long start = System.nanoTime();
for (int i = 0; i < BindgenPerfTest.loops; i++) {
Assert.assertEquals("p", new ChildBinding(c).parent().name().get());
}
this.stop("new binding", start);
}
public void testBindgenReuseExistingBinding() {
Parent p = new Parent("p");
Child c = new Child(p, "c");
ChildBinding cb = new ChildBinding();
Binding<String> b = cb.parent().name();
long start = System.nanoTime();
for (int i = 0; i < BindgenPerfTest.loops; i++) {
cb.set(c);
Assert.assertEquals("p", b.get());
}
this.stop("existing binding", start);
}
public void testBindgenReuseStaticBinding() {
Parent p = new Parent("p");
Child c = new Child(p, "c");
ChildBinding cb = new ChildBinding();
BindingRoot<Child, String> b = cb.parent().name();
long start = System.nanoTime();
for (int i = 0; i < BindgenPerfTest.loops; i++) {
Assert.assertEquals("p", b.getWithRoot(c));
}
this.stop("static binding", start);
}
private void stop(String description, long start) {
System.out.println(StringUtils.leftPad(description, 18) + ": " + StringUtils.leftPad((System.nanoTime() - start) + "ns", 20));
}
}
This should be a reproducible Japex-driven test, but is not yet.