I've set a goal of removing Javassist from Tapestry 5 and I've made
some nice advances on that front. Tapestry uses Javassist inside the
web framework layer to load and transform component classes.
All that code is now rewritten to updated APIs that no longer directly
expose Javassist technology. In other words, where in the past, the
transformer code would write psuedo-Java and add it to a method using
Javassist (for example adding value = null; to the
containingPageDidDetach() method), Tapestry 5.2 will instead add advice
to the (otherwise empty) containingPageDidDetach() method, and the
advice will use a FieldAccess object to set the value field to null.
Basically, I've vastly reduced the number of operations possible using
the ClassTransformation API. Before, it was pretty much unbounded due
to the expressive power of Javassist. Now a small set of operations
exist that can be combined into any number of desired behaviors:
- Add new implemented interfaces to a component Class
- Add new fields to a Class
- Initialize the value of a field to a fixed value, or via a
per-instance callback
- Delegate read and write access to a field to a provided
FieldValueConduit delegate
- Add new methods to a component Class with empty implementations
- Add advice to any method of a class
- Create a MethodAccess object from a method, to allow a method to be
invoked (regardless of visibility)
- Create a FieldAccess object from a field, to allow the field to be
read or updated (regardless of visibility)
What's amazing is that these few operations, combined in different
ways, supports all the different meta-programming possible in Tapestry
5.1. There's costs and benefits to this new approach. Costs
There will be many more objects associated with each component class:
new objects to represent advice on methods, and new objects to provide
access to private component fields and methods.
Javassist could be brutally efficient, the new approach adds several
layers of method invocation that was not present in 5.1.
Incorrect use of method advice can corrupt or disable logic provided by
the framework and is hard to debug. Benefits
We can eventually switch out Javassist for a more stable, more
mainstream, better supported framework such as ASM. ASM should have
superior performance to Javassist (no tedious Java-ish parse and
compile, just raw bytecode manipulation).
The amount of generated bytecode is lower is many cases. Fewer methods
and fields to accomplish the same behavior.
The generated bytecode is more regular across different utilizations:
fewer edge cases, less untested, generated bytecode
Key logic returns to "normal" code space, rather than being indirectly
generated into "Javassist" code space ... this is easier to debug as
there's some place to put your breakpoints! Summary
Overall, I'm pretty happy with what's been put together so far. In the
long run, we'll trade instantiation of long lived objects for dynamic
bytecode generation. There's much more room to create ways to optimize
memory utilization and overall resource utilization and the coding
model is similar (closures and callbacks vs. indirect programming via
Javassist script). I'm liking it!

--
Posted By Howard to Tapestry Central at 2/19/2010 05:55:00 PM

Reply via email to