Evolving the Meta Programming in Tapestry 5

Posted by: Howard Lewis Ship on 02/19/2010

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!


About Howard Lewis Ship

Howard Lewis Ship

Howard Lewis Ship is the creator and lead developer for the Apache Tapestry project, and is a noted expert on Java framework design and developer productivity. He has over twenty years of full-time software development under his belt, with over ten years of Java. He cut his teeth writing customer support software for Stratus Computer, but eventually traded PL/1 for Objective-C and NeXTSTEP before settling into Java.

Howard is respected in the Java community as an expert on web application development, dependency injection, Java meta-programming, and developer productivity. He is a frequent speaker at JavaOne, NoFluffJustStuff, ApacheCon and other conferences, and the author of "Tapestry in Action" for Manning (covering Tapestry 3.0). Lately, he's been dipping his toes into alternate languages, including Clojure.

Howard is an independent consultant, offering Tapestry training, mentoring and project work as well as training in Clojure. He lives in Portland, Oregon with his wife Suzanne, and his son, Jacob.

More About Howard »

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 7
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 3
  • Automation Tools: Git, Hudson, Sonar
  • HTML5, Ajax, jQuery, Usability
  • Mobile Applications - iPhone and Android
  • More...
Learn More »

NFJS, the Magazine

December Issue Now Available
  • BDD and REST

    by Brian Sletten
  • Mocks and Stubs in Groovy Tests

    by Kenneth Kousen
  • Algorithms for Better Text Search Results

    by John Griffin
  • Knowns and Unknowns of Scrum and Agile

    by Brian Tarbox
Learn More »