This library is an extension to Tapestry 4.0 that provides an additional binding prefix, "prop:". This binding prefix is used to access properties of a page or component.
This may seem no different than the built-in "ognl:" prefix, but (unlike OGNL), the underlying access does not use reflection; instead, bytecode enhancement is used to build a custom class that can read and update the named property.
The prop: prefix can only be used to access simple properties, or property paths (a sequence of property names separated by periods). Thus "prop:userName" or "prop:identity.admin" are protential references.
The final property may be read-only or write-only, in which case an appropriate exception will be thrown if the property is updated or read, respectively.
Tapestry 5 uses a more sophisticated version of the "prop:" prefix as its true default (OGNL is an add-on which, as of this writing, has not yet been implemented).
All that's necessary is for the tapestry-prop JAR to be on the class path (typically, packaged inside the WEB-INF/lib folder of the WAR). Maven will, of course, do this for you, just by making tapestry-prop a project dependency.
You may then use the "prop:" prefix. In an HTML template file:
<span jwcid="@Insert" value="prop:userName">Joe User</span>
Or, inside a page or component specification file:
<component id="userName" type="Insert"> <binding name="value" value="prop:userName"/> </component>
The library is compiled for, and compatible with, JDK 1.3.
The "prop:" binding prefix is more efficient than the "ognl:" binding prefix, but less flexible.
On the plus side, there's a big efficiency gain to be had. This is not only the cost of reflection, but the cost of creating temporary objects used by OGNL. Further, any use of OGNL involves some small amount of synchronization. Reflection is still between 5x and 10x as expensive as ordinary method calls.
The down side is that OGNL always evaluates properties in terms of the object's actual type. The "prop:" binding prefix uses the declared type, just as build-time, compiled Java code would. Thus if a page property is an interface, you can't access properties defined by the implementation of that interface (unless those methods are, in fact, defined in the interface).
OGNL also contains a more richly defined type conversion system and, of course, has a much richer syntax. There will always be cases in Tapestry where OGNL is the easiest and most effective way to accomplish a goal without resorting to Java code.
In terms of performance, there's a pretty marked difference:
This figure shows iterations of a get option for a simple case (single property) and a complex case (a property path). Higher values are better (they are the number of iterations in two seconds of clock time).
Doing the work in pure Java code is neck and neck with using the "prop:" binding prefix, and OGNL is clearly slower. Worse, each additional term in the OGNL expression makes a big difference (whereas, for the other two strategies, additional terms have almost no effect). Mutliply this by the hundreds or thousands of such operations in a typical Tapestry page and the difference is quite clear!
The Tapestry configuration property org.apache.tapestry.default-binding-prefix can be used on a page or component to set the default binding prefix. Example:
<page-specification> <meta key="org.apache.tapestry.default-binding-prefix" value="prop"/> . . .
This means that all values in the page specification that don't have an explicit prefix will use "prop:", rather than "ognl:". By moving the <meta> tag to the application specification, this can take effect for all the application pages and components.
Version 1.0.0 is now available. If you don't care for Maven, you may access the binary and source distribution files at http://howardlewisship.com/downloads/tapestry-javaforge/.