ATTENTION: This blog has moved to a new location. Please update your bookmarks, browsing habits, and aggregators.
|
|
Tuesday, June 3, 2003 |
Better Living and Poor-Man's Delegates through Byte Code EngineeringThis post (and this weblog) has a new home. A recent ONJava article by Steven Lewis and Wilhelm Fitzpatrick on delegates caught my interest. Delegation is the ability to treat methods as objects, and the usual application is casting an object to a delegate for one of its methods to get a uniform invocation across an enumeration or collection. Delegation should also be regarded as a potential cross-cutting concern. MotivationOne of our developers came across a delegation-like problem working with Castor for XML binding. The classes that Castor generates all have marshal(...) and unmarshal(...) methods, but the classes don't implement any common interface that would allow the classes to be dealt with in a uniform fashion (that doesn't rely on reflection). (I don't know if this is a sin of omission or comission on their part; omission is my guess.) The desired operation would be: ((Marshallable) foo).marshal(...) If we had delegates to work with, this wouldn't be an issue, but we don't. BackgroundThe overall application is a content management system for technical documentation that includes some Struts-based wizards for generating simple documents. (FiveSight Business Process Integrator and X-Hive/DB do the heavy lifting for the CMS as a whole.) The object model for the wizards is generated by a combination of Ant tasks that use James Clark's excellent Trang and some XSLT to feed XML Schemas to Castor, which then produces Java source code. The challenge then is:
SolutionThe solution was to use BCEL to post-process the Castor-generated classes after they are compiled to byte code, as follows. I'll omit the packaging for the Ant task. (It is left as an exercise for the reader...) The first step is to read the methods off the marker interface named iface:
(The variable _classes is the directory containing the compiled classes for the marker interface(s).) The next step is to scan the classes to be marked and determine if they can implement the interface. This is the fragment of code that processes the class named name from the directory base. (The directory walking code is left as an exercise for the reader...)
That's it, up to packaging. Application to DelegatesThe application of this technique to delegates is straightforward: Create a one-method interface for the desired delegate, and then let the build take care of applying it to the compiled classes. 11:34:22 AM |

