This post originated from an RSS feed registered with Java Buzz
by Thomas Gideon.
Original Post: Navel Epiphany, BeanUtils Still Sucks
Feed Title: Command Line Interface
Feed URL: http://www.gideonfamily.org/roller/rss/cmdln?catname=Java
Feed Description: The blog of a programmer-hacktivist-curmudgeon who occasional rants about society, work, and technology, among other things. Now how do I get to a command prompt on this thing?
Feel pretty satisfied with myself with the 0.2 release of Navel, I figured all I had left was to figure out how to hook BeanManipulator into the Struts 1.1 controller and maybe come up with a scheme to use DelegateBeanHandler to support an interface only or abstract daughter of ActionForm. So I merrily download the Struts 1.1 sources and dig on in.
Turns out that I have to replace or subclass only two classes, RequestProcessor and RequestUtils. I really only want to replace the one line in RequestUtils that calls BeanUtils.populate() with BeanManipulator.populateBean(). I ended up digging into BeanUtils, to refresh my memory and partly to satisfy my curiosity as to whether this code had improved since I last reviewed it some months ago.
Well, the BeanUtils code is still ugly--inconsistently styled, to start with, inexcusable in this day and age of automated code stylers. Then, the classes are a bit larger than I am comfortable with and do not really show the marks of constant polishing via continual re-factoring. I marveled at how brittle all of the type specific code is, from value conversion (I like my PropertyEditor solution far better) to dealing with custom property types, like a Map based property type with extensions similar to the out of the box indexed property support. While they provide for Map based properties, it is basically hard-coded in. There's no way to add in a Set or List based property or any other kind of custom property other than to hack the sources.
That was my first epiphany. I had already felt a little grouchy about only supporting simple and indexed properties in Navel but couldn't think of a generic way to reflect on more complex, custom properties. Then I realized I do not have to. I just have to provide a place for the Bean author to insert logic that concretely knows about any custom properties they've bundled into their own BeanInfo implementation. Duh!
So I quickly re-factored about 70% of the code out of BeanManipulator into a small tree rooted off of a new PropertyManipulator class. The tree establishes a nice Strategy Pattern, into which I injected the re-factored code for simple and indexed properties that I already had. Voila, I had SimplePropertyManipulator and IndexedPropertyManipulator and all my unit tests passed without alteration! Now, a Bean author just has to extend PropertyManipulator, which just requires handleRead() and handleWrite(), and register it with PropertyManipulator using the Class for their custom PropertyDescriptor. BeanManipulator will find and use their custom PropertyManipulator whenever it encounters their custom PropertyDescriptor. How easy can I make it?
Heady with my success, I turned to an artifact that PMD had been bitching about in the two handler classes' constructors. I had some intertangled, overridden methods for validating that each handler could indeed fully support the proxied class. PMD didn't like that the constructors were calling local methods that could be overridden. I had dickered around with making these final earlier but with no success in quieting PMD. Still in major re-factoring mode, I realized I could extract all of the validation code completely from the handler classes, having the delegate validation logic extend the property validation logic, just overriding the one method it needed to.
So PropertyValidator and DelegateValidator in the beans.validation package were born. Each of the validators is more coupled than usual with its associated handler class, but I think this is acceptable and it eliminates the risk of anything funny going on down the line should someone else extend either PropertyBeanHandler or DelegateBeanHandler.
At this point, I have a few more TODO items, including the Struts wiring work that started this whole round of re-factoring. I want to provide an example List or Map based PropertyDescriptor along with a matching daughter of PropertyManipulator, to show how that can be extended as well as writing more unit tests to more fully exercise the new code. I also want to write some unit tests around the PropertyEditor improvements, make sure it works as I planned and as outlined in the JavaBeans spec. Once I've completed these, I will release 0.3. At that point, I'd like to enlist some testers and start going into heavy bug fix mode, ramping up towards perhaps a 1.0 launch. My goal there is to have code that is genuinely useful for Bean use in a web environment, in particular but not limited to Struts.