On the flight out to CodeMash I started working on some refinements to how Tapestry does runtime class transformation. My long term goal is to move away from Javassist and towards something a bit simpler ... like ASM. Why? Javassist does not have a good, responsive, supportive community, and it has been increasingly flaky since JDK 1.6.
Previously, I've blogged about how invaluable Javassist is, and I stand behind that early pronouncement. Tapestry IoC and Tapestry Core both use Javassist extensively to create new classes at runtime, as well as modify classes as they are loaded into memory. However, I've also been finding new ways to apply meta-programming without exposing all the gory details of Javassist. As usual, simplicity follows complexity: I'm finding ways to simplify work I've done the hard way, previously, to make these techniques easier for others to leverage.
That's the pattern I'm trying for: none of the explicit Java psuedo-code used by Javassist, instead, defining ways to add behavior to methods, or individual fields, in terms of simple callback interfaces. For the moment, the under-the-covers wiring is still Javassist (underneath the Tapestry ComponentClassTransformation interface), but eventually all the parts that are truly tied to Javassist (i.e., those parts of the API where a Javassist pseudo-code string are provided) can be phased out, deprecated, and eliminated.
The advantage of this revised approach is that the amount of runtime-generated code decreases and simplifies. Less behavior is created via Javassist pseudo-code, and fewer fields need to be created or injected into the component class. Further, more runtime code will be in standard objects, compiled by the standard Java compiler, and less code will be compiled by Javassist. Intuitively speaking (always dangerous), it makes sense that standard Java code will be optimized better by Hotspot: Reportedly, some aspects of Hotspot are tied to the exact form of bytecode produced by the Sun Java compiler).
I've heard from some specific Tapestry users who are building and deploying very large, very complicated applications, that live class reloading is problematic for them to use: their pages consist of hundreds (possibly thousands) of deeply nested components, and they are seeing 30+ second delays reloading a page after a change. Whenever a component class changes, Tapestry must discard the old ClassLoader, and create a new one, and lazily re-instrument all the component classes; this isn't a big deal with only dozens of pages and components, but I want Tapestry to be effective even for the largest, most complicated web applications. Simplifying and revising Tapestry's approach to bytecode enhancement is just the latest in a series of internal changes targeting improved performance.
Meanwhile. the CodeMash conference goes on around me ... and shortly, back to the waterpark.