Friday 9 January 2009

Migrating to the Bean Validation Framework

Yesterday, I had a good look around to see if the conflict between Spring and Commons Validator had been resolved from either side. I didn't find any evidence, so have attempted to contact Colin Yates who announced the last SM 0.9 release.

To give myself a solid base, I've upgraded my old versions of SM and Commons Validator to their current releases (0.9 and 1.3.1). It was nice to see that the Commons team do thank people in person for their contributions, in my case a fix to the DTD for version 1.2.0.

These upgrades needed a little API tweaking. The package org.springmodules.commons.validator was renamed to org.springmodules.validation.commons, so my derived classes and XML needed a quick search and replace, but that was about it.

Sure enough, when I deployed my build to Tomcat, the old problem exists, so it's time to crack on with migration.

My strategy is to use the power of Spring's dependency injection. I have a number of Spring Validators, including our own custom validators for multi-page forms. For now, though, I'll start with the easy test, of migrating the DefaultBeanValidator to the Bean Validation Framework. In each of these cases, I'm going to leave the old code and configuration intact, and just inject the new validators in place of the old. This way, backing out will be as simple as reverting just my bean definition XML.  And, naturally, the one other thing.  The difference between using [] for access to maps and ()!

Wednesday 7 January 2009

In Need Of Validation - The 2005 Approach

Back in 2005, when we kicked off our project, we wanted to leverage the Commons Validator (at the time the most obvious choice for us) for validating form input.

For a typical form, such as validating a registration, this is pretty straightforward. On our site, we've minimalist, we only ask for a name and an email address, and we then send out a generated password that can be changed.

Hence, our login bean, SignUpCmd, has only two required fields: name and email.

The respective entry in validation.xml is not simple:


<form name="signUpCmd">
<field property="name" depends="required,minlength,maxlength,mask">
<msg name="required" key="forms.errors.requiredAndMinLength">
<msg name="mask" key="account.errors.nameSyntax">
<arg position="0" key="account.name.displayname">
<arg position="1" name="minlength" key="${var:minlength}" resource="false">
<arg position="1" name="required" key="${var:minlength}" resource="false">
<arg position="1" name="maxlength" key="${var:maxlength}" resource="false">
<var>
<var-name>minlength</var-name>
<var-value>${nameMinLength}</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>${nameMaxLength}</var-value>
</var>
<var>
<var-name>mask</var-name>
<var-value>${screenNameMask}</var-value>
</var>
</field>
<field property="email" depends="required,maxlength,email">
<arg position="0" key="account.email.displayname">
<arg position="1" name="maxlength" key="${var:maxlength}" resource="false">
<var>
<var-name>maxlength</var-name>
<var-value>${emailMaxLength}</var-value>
</var>
</field>



Hmm... I can recall now why I was starting to wonder about the logic of this approach!

This was just the start. Most of our form editing and validation requirements involved flexible content, with the data entries stored in a map, named 'values'.

The result was that in order to extend our application, we had no need to change any Java code, we updated: our content definitions (e.g. adding a new enumerated attribute "Thoughts on the Matrix" to a dating profile with the options: "Not seen it", "If only they'd stopped at one", "Loved them all", "What's the Matrix?"), adding a single <wwm-form:enum> tag to the JSP for editing and displaying that content and, adding an entry into validation.xml.

And, it's at validation where we hit a critical problem: that Commons Validator references a map as values(viewsOnTheMatrix), but Spring's BeanWrapperImpl accesses maps (and arrays too) as values[viewsOnTheMatrix].

After some searching around, we found that it was a supposedly fixed bug: http://jira.springframework.org/browse/MOD-83, and on finding it wasn't, we found the only way forwards was to patch Spring ourselves to support the same approach as Commons Validator. Our patch is included in my comment in the above bug.

This has served us well for a number of years, with the caveat that each time we upgrade, we have to patch the source for spring-beans.jar.

Searching the forums, it's clear that we're not the only ones facing this difficulty with maps. The big issue for me, though is that with such a pluggable system, such as Spring, we should be able to get this sorted. There are a couple of approaches that I'm taking on this:
That task, though, will have to wait. I've got a birthday curry to go to!

A New Commitment

It's been 4 years since I started using Spring. We chose the Spring Framework, back in 2005, because at the time Spring MVC looked the best web framework for our needs.

Looking back, I can see now how little we truly grasped the stength of Spring's dependency injection model. If we had, I think we may well have architected our database engine, and application layer on Spring.

And, it must be said, hindsight is an easy thing. Back in Spring 1.2, there was no session scope for beans, so the session implementation of our application layer was home spun. There were not that many articles that really nailed the advantages of adopting Spring throughout.

Now, things are different. Spring has evolved, people have raved, and we've learned.

Personally, the lessons have lead me to take a Spring seriously, and to get out there helping others to do the same. Part of that is to do some writing, not just blogging, but in helping on the Spring Forums, and also, submitting some patch proposals to the Spring team.

Another aspect of this new direction is that I'm now looking to break down the web and application code that runs Fridge Mountain into independent, useful and reusable POJO-based modules. This project will allow me to get up to speed on the latest enhancements in Spring 2.5 (and 3.0 as it progresses), and, hopefully help some others along the way.